Merge "Upgrade libyuv to 5f284054cb806f82e737f738003d764277970d45" into main
diff --git a/.vpython b/.vpython
deleted file mode 100644
index 4a64fd2..0000000
--- a/.vpython
+++ /dev/null
@@ -1,52 +0,0 @@
-# This is a vpython "spec" file.
-#
-# It describes patterns for python wheel dependencies of the python scripts in
-# the chromium repo, particularly for dependencies that have compiled components
-# (since pure-python dependencies can be easily vendored into third_party).
-#
-# When vpython is invoked, it finds this file and builds a python VirtualEnv,
-# containing all of the dependencies described in this file, fetching them from
-# CIPD (the "Chrome Infrastructure Package Deployer" service). Unlike `pip`,
-# this never requires the end-user machine to have a working python extension
-# compilation environment. All of these packages are built using:
-#   https://chromium.googlesource.com/infra/infra/+/master/infra/tools/dockerbuild/
-#
-# All python scripts in the repo share this same spec, to avoid dependency
-# fragmentation.
-#
-# If you have depot_tools installed in your $PATH, you can invoke python scripts
-# in this repo by running them as you normally would run them, except
-# substituting `vpython` instead of `python` on the command line, e.g.:
-#   vpython path/to/script.py some --arguments
-#
-# Read more about `vpython` and how to modify this file here:
-#   https://chromium.googlesource.com/infra/infra/+/master/doc/users/vpython.md
-
-python_version: "2.7"
-
-# Used by:
-#   third_party/catapult
-wheel: <
-  name: "infra/python/wheels/psutil/${platform}_${py_python}_${py_abi}"
-  version: "version:5.2.2"
->
-
-# Used by:
-#   third_party/catapult
-wheel: <
-  name: "infra/python/wheels/pypiwin32/${vpython_platform}"
-  version: "version:219"
-  match_tag: <
-    platform: "win32"
-  >
-  match_tag: <
-    platform: "win_amd64"
-  >
->
-
-# Used by:
-#   build/android
-wheel: <
-  name: "infra/python/wheels/requests-py2_py3"
-  version: "version:2.13.0"
->
diff --git a/.vpython3 b/.vpython3
index 28d819e..4670786 100644
--- a/.vpython3
+++ b/.vpython3
@@ -42,8 +42,8 @@
 #   build/android/pylib/local/emulator/avd.py
 #   components/policy/test_support/policy_testserver.py
 wheel: <
-  name: "infra/python/wheels/protobuf-py2_py3"
-  version: "version:3.15.8"
+  name: "infra/python/wheels/protobuf-py3"
+  version: "version:4.25.1"
 >
 
 # TODO(https://crbug.com/898348): Add in necessary wheels as Python3 versions
@@ -184,7 +184,11 @@
 >
 wheel: <
   name: "infra/python/wheels/urllib3-py2_py3"
-  version: "version:1.24.3"
+  version: "version:1.26.6"
+>
+wheel: <
+  name: "infra/python/wheels/brotli/${vpython_platform}"
+  version: "version:1.0.9"
 >
 wheel: <
   name: "infra/python/wheels/blessings-py2_py3"
diff --git a/AUTHORS b/AUTHORS
index 28c0895..b272adf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -3,4 +3,5 @@
 
 Google Inc.
 
+Ho Cheung <uioptt24@gmail.com>
 Ivan Pavlotskiy <ivan.pavlotskiy@lgepartner.com>
diff --git a/Android.bp b/Android.bp
index e93b4b1..bb7026b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -76,12 +76,26 @@
         "-fexceptions",
         "-DHAVE_JPEG",
         "-DLIBYUV_UNLIMITED_DATA",
+        // TODO: enable these...
+        "-DLIBYUV_DISABLE_SME",
+        "-DLIBYUV_DISABLE_SVE",
     ],
 
     arch: {
         arm: {
             cflags: ["-mfpu=neon"],
         },
+        arm64: {
+            cflags: [
+                "-Xclang -target-feature",
+                // This comment prevents bpfmt from sorting the flags incorrectly.
+                "-Xclang +dotprod",
+                // This comment prevents bpfmt from sorting the flags incorrectly.
+                "-Xclang -target-feature",
+                // This comment prevents bpfmt from sorting the flags incorrectly.
+                "-Xclang +i8mm",
+            ],
+        },
     },
 
     shared_libs: ["libjpeg"],
@@ -99,6 +113,10 @@
     lto: {
         never: true,
     },
+    // TODO: enable this...
+//    sanitize: {
+//        cfi: true,
+//    },
 }
 
 // compatibilty static library until all uses of libyuv_static are replaced
diff --git a/BUILD.gn b/BUILD.gn
index 2c600b2..649249d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -29,10 +29,18 @@
       ldflags = [ "-Wl,--dynamic-linker,/system/bin/linker64" ]
     }
   }
-  defines = []
+
+  # Define CHROMIUM to tell cpu_id to avoid sandbox unsafe system calls.
+  defines = [ "CHROMIUM" ]
   if (!libyuv_use_neon) {
     defines += [ "LIBYUV_DISABLE_NEON" ]
   }
+  if (!libyuv_use_sve) {
+    defines += [ "LIBYUV_DISABLE_SVE" ]
+  }
+  if (!libyuv_use_sme) {
+    defines += [ "LIBYUV_DISABLE_SME" ]
+  }
   if (libyuv_disable_rvv) {
     defines += [ "LIBYUV_DISABLE_RVV" ]
   }
@@ -76,6 +84,14 @@
     deps += [ ":libyuv_neon" ]
   }
 
+  if (libyuv_use_sve) {
+    deps += [ ":libyuv_sve" ]
+  }
+
+  if (libyuv_use_sme) {
+    deps += [ ":libyuv_sme" ]
+  }
+
   if (libyuv_use_msa) {
     deps += [ ":libyuv_msa" ]
   }
@@ -104,11 +120,14 @@
     "include/libyuv.h",
     "include/libyuv/basic_types.h",
     "include/libyuv/compare.h",
+    "include/libyuv/compare_row.h",
     "include/libyuv/convert.h",
     "include/libyuv/convert_argb.h",
     "include/libyuv/convert_from.h",
     "include/libyuv/convert_from_argb.h",
     "include/libyuv/cpu_id.h",
+    "include/libyuv/loongson_intrinsics.h",
+    "include/libyuv/macros_msa.h",
     "include/libyuv/mjpeg_decoder.h",
     "include/libyuv/planar_functions.h",
     "include/libyuv/rotate.h",
@@ -217,23 +236,45 @@
 
     public_configs = [ ":libyuv_config" ]
 
-    # Always enable optimization for Release and NaCl builds (to workaround
-    # crbug.com/538243).
-    if (!is_debug) {
-      configs -= [ "//build/config/compiler:default_optimization" ]
-
-      # Enable optimize for speed (-O2) over size (-Os).
-      # TODO(fbarchard): Consider optimize_speed which is O3.
-      configs += [ "//build/config/compiler:optimize_max" ]
-    }
-
-    if (current_cpu != "arm64") {
+    if (current_cpu == "arm64") {
+      cflags = [ "-march=armv8-a+dotprod+i8mm" ]
+    } else {
       configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
       cflags = [ "-mfpu=neon" ]
     }
   }
 }
 
+if (libyuv_use_sve) {
+  static_library("libyuv_sve") {
+    sources = [ "source/row_sve.cc" ]
+
+    deps = [ ":libyuv_internal" ]
+
+    public_configs = [ ":libyuv_config" ]
+
+    # SVE2 is an Armv9-A feature.
+    cflags = [ "-march=armv9-a+sve2" ]
+  }
+}
+
+if (libyuv_use_sme) {
+  static_library("libyuv_sme") {
+    sources = [
+      "source/rotate_sme.cc",
+      "source/row_sme.cc",
+      "source/scale_sme.cc",
+    ]
+
+    deps = [ ":libyuv_internal" ]
+
+    public_configs = [ ":libyuv_config" ]
+
+    # SME is an Armv9-A feature.
+    cflags = [ "-march=armv9-a+sme" ]
+  }
+}
+
 if (libyuv_use_msa) {
   static_library("libyuv_msa") {
     sources = [
@@ -354,6 +395,9 @@
 
     if (is_linux || is_chromeos) {
       cflags = [ "-fexceptions" ]
+
+      # For enabling ASLR.
+      ldflags = [ "-pie" ]
     }
     if (is_ios) {
       configs -= [ "//build/config/compiler:default_symbols" ]
@@ -363,9 +407,6 @@
     if (!is_ios && !libyuv_disable_jpeg) {
       defines += [ "HAVE_JPEG" ]
     }
-    if (is_android) {
-      deps += [ "//testing/android/native_test:native_test_native_code" ]
-    }
 
     # TODO(YangZhang): These lines can be removed when high accuracy
     # YUV to RGB to Neon is ported.
diff --git a/CM_linux_packages.cmake b/CM_linux_packages.cmake
index a073edf..4caf156 100644
--- a/CM_linux_packages.cmake
+++ b/CM_linux_packages.cmake
@@ -1,6 +1,7 @@
 # determine the version number from the #define in libyuv/version.h
 EXECUTE_PROCESS (
-	COMMAND grep --perl-regex --only-matching "(?<=LIBYUV_VERSION )[0-9]+" include/libyuv/version.h
+	COMMAND grep -Eo "LIBYUV_VERSION\ [0-9]+" include/libyuv/version.h
+	COMMAND grep -Eo "[0-9]+"
 	WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
 	OUTPUT_VARIABLE YUV_VERSION_NUMBER
 	OUTPUT_STRIP_TRAILING_WHITESPACE )
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9abfa74..5df7685 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,53 +1,200 @@
 # CMakeLists for libyuv
 # Originally created for "roxlu build system" to compile libyuv on windows
-# Run with -DTEST=ON to build unit tests
+# Run with -DUNIT_TEST=ON to build unit tests
 
-PROJECT ( YUV C CXX )	# "C" is required even for C++ projects
-CMAKE_MINIMUM_REQUIRED( VERSION 2.8.12 )
-OPTION( UNIT_TEST "Built unit tests" OFF )
+include(CheckCSourceCompiles)
 
-SET ( ly_base_dir	${PROJECT_SOURCE_DIR} )
-SET ( ly_src_dir	${ly_base_dir}/source )
-SET ( ly_inc_dir	${ly_base_dir}/include )
-SET ( ly_tst_dir	${ly_base_dir}/unit_test )
-SET ( ly_lib_name	yuv )
-SET ( ly_lib_static	${ly_lib_name} )
-SET ( ly_lib_shared	${ly_lib_name}_shared )
+project ( YUV C CXX )	# "C" is required even for C++ projects
+cmake_minimum_required( VERSION 2.8.12 )
+option( UNIT_TEST "Built unit tests" OFF )
 
-FILE ( GLOB_RECURSE	ly_source_files ${ly_src_dir}/*.cc )
-LIST ( SORT			ly_source_files )
+set ( ly_base_dir	${PROJECT_SOURCE_DIR} )
+set ( ly_src_dir	${ly_base_dir}/source )
+set ( ly_inc_dir	${ly_base_dir}/include )
+set ( ly_tst_dir	${ly_base_dir}/unit_test )
+set ( ly_lib_name	yuv )
+set ( ly_lib_static	${ly_lib_name} )
+set ( ly_lib_shared	${ly_lib_name}_shared )
 
-FILE ( GLOB_RECURSE	ly_unittest_sources ${ly_tst_dir}/*.cc )
-LIST ( SORT			ly_unittest_sources )
+# We cannot use GLOB here since we want to be able to separate out files that
+# need particular flags to enable architecture extensions like AArch64's SVE.
+# TODO: More of these files could be separated out for different architectures.
+set ( ly_common_source_files
+  ${ly_src_dir}/compare.cc
+  ${ly_src_dir}/compare_common.cc
+  ${ly_src_dir}/compare_gcc.cc
+  ${ly_src_dir}/compare_msa.cc
+  ${ly_src_dir}/compare_win.cc
+  ${ly_src_dir}/convert_argb.cc
+  ${ly_src_dir}/convert.cc
+  ${ly_src_dir}/convert_from_argb.cc
+  ${ly_src_dir}/convert_from.cc
+  ${ly_src_dir}/convert_jpeg.cc
+  ${ly_src_dir}/convert_to_argb.cc
+  ${ly_src_dir}/convert_to_i420.cc
+  ${ly_src_dir}/cpu_id.cc
+  ${ly_src_dir}/mjpeg_decoder.cc
+  ${ly_src_dir}/mjpeg_validate.cc
+  ${ly_src_dir}/planar_functions.cc
+  ${ly_src_dir}/rotate_any.cc
+  ${ly_src_dir}/rotate_argb.cc
+  ${ly_src_dir}/rotate.cc
+  ${ly_src_dir}/rotate_common.cc
+  ${ly_src_dir}/rotate_gcc.cc
+  ${ly_src_dir}/rotate_lsx.cc
+  ${ly_src_dir}/rotate_msa.cc
+  ${ly_src_dir}/rotate_win.cc
+  ${ly_src_dir}/row_any.cc
+  ${ly_src_dir}/row_common.cc
+  ${ly_src_dir}/row_gcc.cc
+  ${ly_src_dir}/row_lasx.cc
+  ${ly_src_dir}/row_lsx.cc
+  ${ly_src_dir}/row_msa.cc
+  ${ly_src_dir}/row_rvv.cc
+  ${ly_src_dir}/row_win.cc
+  ${ly_src_dir}/scale_any.cc
+  ${ly_src_dir}/scale_argb.cc
+  ${ly_src_dir}/scale.cc
+  ${ly_src_dir}/scale_common.cc
+  ${ly_src_dir}/scale_gcc.cc
+  ${ly_src_dir}/scale_lsx.cc
+  ${ly_src_dir}/scale_msa.cc
+  ${ly_src_dir}/scale_rgb.cc
+  ${ly_src_dir}/scale_rvv.cc
+  ${ly_src_dir}/scale_uv.cc
+  ${ly_src_dir}/scale_win.cc
+  ${ly_src_dir}/video_common.cc)
 
-INCLUDE_DIRECTORIES( BEFORE ${ly_inc_dir} )
+file ( GLOB_RECURSE	ly_unittest_sources ${ly_tst_dir}/*.cc )
+list ( SORT			ly_unittest_sources )
+
+include_directories( BEFORE ${ly_inc_dir} )
 
 if(MSVC)
-  ADD_DEFINITIONS ( -D_CRT_SECURE_NO_WARNINGS )
+  add_definitions ( -D_CRT_SECURE_NO_WARNINGS )
+endif()
+
+# Need to set PIC to allow creating shared libraries from object file libraries.
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+# Build the set of objects that do not need to be compiled with flags to enable
+# particular architecture features.
+add_library( ${ly_lib_name}_common_objects OBJECT ${ly_common_source_files} )
+set(ly_lib_parts $<TARGET_OBJECTS:${ly_lib_name}_common_objects>)
+
+string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" SYSPROC)
+set(LOONGARCH64_ALIASES loongarch64)
+list(FIND LOONGARCH64_ALIASES "${SYSPROC}" LOONGARCH64MATCH)
+
+if(LOONGARCH64MATCH GREATER "-1")
+  set(LOONGARCH64 1)
+endif()
+
+if(NOT MSVC)
+  string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch_lowercase)
+
+  if(arch_lowercase MATCHES "^arm" AND NOT arch_lowercase STREQUAL "arm64")
+    # Enable Arm Neon kernels.
+    add_definitions(-DLIBYUV_NEON=1)
+    add_library(${ly_lib_name}_neon OBJECT
+      ${ly_src_dir}/compare_neon.cc
+      ${ly_src_dir}/rotate_neon.cc
+      ${ly_src_dir}/row_neon.cc
+      ${ly_src_dir}/scale_neon.cc)
+    target_compile_options(${ly_lib_name}_neon PRIVATE -mfpu=neon)
+    list(APPEND ly_lib_parts $<TARGET_OBJECTS:${ly_lib_name}_neon>)
+  endif()
+
+  if(arch_lowercase STREQUAL "aarch64" OR arch_lowercase STREQUAL "arm64")
+    # Enable AArch64 Neon dot-product and i8mm kernels.
+    add_library(${ly_lib_name}_neon64 OBJECT
+      ${ly_src_dir}/compare_neon64.cc
+      ${ly_src_dir}/rotate_neon64.cc
+      ${ly_src_dir}/row_neon64.cc
+      ${ly_src_dir}/scale_neon64.cc)
+    target_compile_options(${ly_lib_name}_neon64 PRIVATE -march=armv8-a+dotprod+i8mm)
+    list(APPEND ly_lib_parts $<TARGET_OBJECTS:${ly_lib_name}_neon64>)
+
+    # Enable AArch64 SVE kernels.
+    add_library(${ly_lib_name}_sve OBJECT
+      ${ly_src_dir}/row_sve.cc)
+    target_compile_options(${ly_lib_name}_sve PRIVATE -march=armv9-a+sve2)
+    list(APPEND ly_lib_parts $<TARGET_OBJECTS:${ly_lib_name}_sve>)
+
+    set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+    set(OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=armv9-a+sme")
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+    # Check whether the compiler can compile SME functions; this fails
+    # with Clang for Windows.
+    check_c_source_compiles("
+__arm_locally_streaming void func(void) { }
+int main(void) { return 0; }
+    " CAN_COMPILE_SME)
+    set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE ${OLD_CMAKE_TRY_COMPILE_TARGET_TYPE})
+
+    if (CAN_COMPILE_SME)
+      # Enable AArch64 SME kernels.
+      add_library(${ly_lib_name}_sme OBJECT
+        ${ly_src_dir}/rotate_sme.cc
+        ${ly_src_dir}/row_sme.cc
+        ${ly_src_dir}/scale_sme.cc)
+      target_compile_options(${ly_lib_name}_sme PRIVATE -march=armv9-a+sme)
+      list(APPEND ly_lib_parts $<TARGET_OBJECTS:${ly_lib_name}_sme>)
+    else()
+      add_definitions(-DLIBYUV_DISABLE_SME)
+    endif()
+  endif()
+endif()
+
+if(LOONGARCH64)
+  include(CheckCXXSourceCompiles)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-narrowing")
+  check_cxx_source_compiles("
+    int main(int argc, char **argv) {
+      __asm__ volatile (
+         \"vadd.w $vr0, $vr1, $vr1\"
+      );
+    return 0; }" SUPPORTS_LSX)
+
+  check_cxx_source_compiles("
+    int main(int argc, char **argv) {
+      __asm__ volatile (
+         \"xvadd.w $xr0, $xr1, $xr1\"
+      );
+    return 0; }" SUPPORTS_LASX)
+
+  if(SUPPORTS_LSX)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlsx")
+  endif()
+  if(SUPPORTS_LASX)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlasx")
+  endif()
 endif()
 
 # this creates the static library (.a)
-ADD_LIBRARY				( ${ly_lib_static} STATIC ${ly_source_files} )
+add_library( ${ly_lib_static} STATIC ${ly_lib_parts})
 
 # this creates the shared library (.so)
-ADD_LIBRARY				( ${ly_lib_shared} SHARED ${ly_source_files} )
-SET_TARGET_PROPERTIES	( ${ly_lib_shared} PROPERTIES OUTPUT_NAME "${ly_lib_name}" )
-SET_TARGET_PROPERTIES	( ${ly_lib_shared} PROPERTIES PREFIX "lib" )
+add_library( ${ly_lib_shared} SHARED ${ly_lib_parts})
+set_target_properties( ${ly_lib_shared} PROPERTIES OUTPUT_NAME "${ly_lib_name}" )
+set_target_properties( ${ly_lib_shared} PROPERTIES PREFIX "lib" )
 if(WIN32)
-  SET_TARGET_PROPERTIES	( ${ly_lib_shared} PROPERTIES IMPORT_PREFIX "lib" )
+  set_target_properties( ${ly_lib_shared} PROPERTIES IMPORT_PREFIX "lib" )
 endif()
 
 # this creates the cpuid tool
-ADD_EXECUTABLE      ( cpuid ${ly_base_dir}/util/cpuid.c )
-TARGET_LINK_LIBRARIES  ( cpuid ${ly_lib_static} )
+add_executable      ( cpuid ${ly_base_dir}/util/cpuid.c )
+target_link_libraries  ( cpuid ${ly_lib_static} )
 
 # this creates the conversion tool
-ADD_EXECUTABLE			( yuvconvert ${ly_base_dir}/util/yuvconvert.cc )
-TARGET_LINK_LIBRARIES	( yuvconvert ${ly_lib_static} )
+add_executable			( yuvconvert ${ly_base_dir}/util/yuvconvert.cc )
+target_link_libraries	( yuvconvert ${ly_lib_static} )
 
 # this creates the yuvconstants tool
-ADD_EXECUTABLE      ( yuvconstants ${ly_base_dir}/util/yuvconstants.c )
-TARGET_LINK_LIBRARIES  ( yuvconstants ${ly_lib_static} )
+add_executable      ( yuvconstants ${ly_base_dir}/util/yuvconstants.c )
+target_link_libraries  ( yuvconstants ${ly_lib_static} )
 
 find_package ( JPEG )
 if (JPEG_FOUND)
@@ -59,10 +206,11 @@
 if(UNIT_TEST)
   find_library(GTEST_LIBRARY gtest)
   if(GTEST_LIBRARY STREQUAL "GTEST_LIBRARY-NOTFOUND")
-    set(GTEST_SRC_DIR /usr/src/gtest CACHE STRING "Location of gtest sources")
+    set(GTEST_SRC_DIR_DEFAULT /usr/src/gtest)
     if (CMAKE_CROSSCOMPILING)
-      set(GTEST_SRC_DIR third_party/googletest/src/googletest)
+      set(GTEST_SRC_DIR_DEFAULT ${CMAKE_SOURCE_DIR}/third_party/googletest/src/googletest)
     endif()
+    set(GTEST_SRC_DIR ${GTEST_SRC_DIR_DEFAULT} CACHE STRING "Location of gtest sources")
     if(EXISTS ${GTEST_SRC_DIR}/src/gtest-all.cc)
       message(STATUS "building gtest from sources in ${GTEST_SRC_DIR}")
       set(gtest_sources ${GTEST_SRC_DIR}/src/gtest-all.cc)
@@ -98,11 +246,11 @@
 
 
 # install the conversion tool, .so, .a, and all the header files
-INSTALL ( PROGRAMS ${CMAKE_BINARY_DIR}/yuvconvert			DESTINATION bin )
-INSTALL ( TARGETS ${ly_lib_static}						DESTINATION lib )
-INSTALL ( TARGETS ${ly_lib_shared} LIBRARY				DESTINATION lib RUNTIME DESTINATION bin )
-INSTALL ( DIRECTORY ${PROJECT_SOURCE_DIR}/include/		DESTINATION include )
+install ( TARGETS yuvconvert DESTINATION bin )
+install ( TARGETS ${ly_lib_static}						DESTINATION lib )
+install ( TARGETS ${ly_lib_shared} LIBRARY DESTINATION lib RUNTIME DESTINATION bin ARCHIVE DESTINATION lib )
+install ( DIRECTORY ${PROJECT_SOURCE_DIR}/include/		DESTINATION include )
 
 # create the .deb and .rpm packages using cpack
-INCLUDE ( CM_linux_packages.cmake )
+include ( CM_linux_packages.cmake )
 
diff --git a/DEPS b/DEPS
index 70ed1d5..ecc8001 100644
--- a/DEPS
+++ b/DEPS
@@ -5,39 +5,49 @@
 
 vars = {
   'chromium_git': 'https://chromium.googlesource.com',
-  'chromium_revision': 'af3d01376bec75a68f90160bfd38057d60510a2b',
-  'gn_version': 'git_revision:fae280eabe5d31accc53100137459ece19a7a295',
+  'chromium_revision': '908f3898afdb1fca9352cf3827168a66ff914084',
+  'gn_version': 'git_revision:c97a86a72105f3328a540f5a5ab17d11989ab7dd',
   # ninja CIPD package version.
   # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
-  'ninja_version': 'version:2@1.11.1.chromium.6',
+  'ninja_version': 'version:3@1.12.1.chromium.4',
   # reclient CIPD package version
-  'reclient_version': 're_client_version:0.110.0.43ec6b1-gomaip',
+  'reclient_version': 're_client_version:0.172.0.3cf60ba5-gomaip',
+  # Fetch configuration files required for the 'use_remoteexec' gn arg
+  'download_remoteexec_cfg': False,
+  # RBE instance to use for running remote builds
+  'rbe_instance': Str('projects/rbe-webrtc-developer/instances/default_instance'),
+  # RBE project to download rewrapper config files for. Only needed if
+  # different from the project used in 'rbe_instance'
+  'rewrapper_cfg_project': Str(''),
 
   # Keep the Chromium default of generating location tags.
   'generate_location_tags': True,
 
   # By default, download the fuchsia sdk from the public sdk directory.
   'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/core/',
-  'fuchsia_version': 'version:15.20230909.2.1',
+  'fuchsia_version': 'version:26.20250103.4.1',
   # By default, download the fuchsia images from the fuchsia GCS bucket.
   'fuchsia_images_bucket': 'fuchsia',
   'checkout_fuchsia': False,
   # Since the images are hundreds of MB, default to only downloading the image
   # most commonly useful for developers. Bots and developers that need to use
   # other images can override this with additional images.
-  'checkout_fuchsia_boot_images': "terminal.qemu-x64,terminal.x64",
+  'checkout_fuchsia_boot_images': "terminal.x64",
   'checkout_fuchsia_product_bundles': '"{checkout_fuchsia_boot_images}" != ""',
+
+  # condition to allowlist deps for non-git-source processing.
+  'non_git_source': 'True',
 }
 
 deps = {
   'src/build':
-    Var('chromium_git') + '/chromium/src/build' + '@' + '5885d3c24833ad72845a52a1b913a2b8bc651b56',
+    Var('chromium_git') + '/chromium/src/build' + '@' + 'f3e95cc9a07a76a7700eec429dacf0ea55cf9c01',
   'src/buildtools':
-    Var('chromium_git') + '/chromium/src/buildtools' + '@' + '79ab87fa54614258c4c95891e873223371194525',
+    Var('chromium_git') + '/chromium/src/buildtools' + '@' + 'dc741883264b58654396d30d5b8d077d4d7d758f',
   'src/testing':
-    Var('chromium_git') + '/chromium/src/testing' + '@' + '51e9a02297057cc0e917763a51e16680b7d16fb6',
+    Var('chromium_git') + '/chromium/src/testing' + '@' + '4341e4d7a272f95394094b48f1edf1ab7e33c61f',
   'src/third_party':
-    Var('chromium_git') + '/chromium/src/third_party' + '@' + '2dc4b18abd1003ce7b1eda509dc96f12d49a9667',
+    Var('chromium_git') + '/chromium/src/third_party' + '@' + 'f25a92da849d82fd0adfee562b04bccf1d9a9a03',
 
   'src/buildtools/linux64': {
     'packages': [
@@ -83,9 +93,9 @@
   },
 
   'src/third_party/catapult':
-    Var('chromium_git') + '/catapult.git' + '@' + 'fa05d995e152efdae488a2aeba397cd609fdbc9d',
+    Var('chromium_git') + '/catapult.git' + '@' + '8491e07230d983b9eb55cdfbf075f0a9d4fb5d28',
   'src/third_party/clang-format/script':
-      Var('chromium_git') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + 'f97059df7f8b205064625cdb5f97b56668a125ef',
+      Var('chromium_git') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + '37f6e68a107df43b7d7e044fd36a13cbae3413f2',
   'src/third_party/colorama/src':
     Var('chromium_git') + '/external/colorama.git' + '@' + '3de9f013df4b470069d03d250224062e8cf15c49',
   'src/third_party/cpu_features/src': {
@@ -93,29 +103,34 @@
     'condition': 'checkout_android',
   },
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd3e43dd4319ba169c0aaf44547eecf861f2fe5da',
-  'src/third_party/freetype/src':
-    Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + '9e3c5d7e183c1a8d5ed8868d7d28ef18d3ec9ec8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '423f1e1914ab4aa7b2bdf804e216d4c097853ba2',
   'third_party/fuchsia-gn-sdk': {
     'url': Var('chromium_git') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + '0d6902558d92fe3d49ba9a8f638ddea829be595b',
     'condition': 'checkout_fuchsia',
   },
   'src/third_party/googletest/src':
-    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + 'af29db7ec28d6df1c7f0f745186884091e602e07',
+    Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '7d76a231b0e29caf86e68d1df858308cd53b2a66',
   'src/third_party/harfbuzz-ng/src':
-    Var('chromium_git') + '/external/github.com/harfbuzz/harfbuzz.git' + '@' + 'db700b5670d9475cc8ed4880cc9447b232c5e432',
+    Var('chromium_git') + '/external/github.com/harfbuzz/harfbuzz.git' + '@' + '1c249be96e27eafd15eb86d832b67fbc3751634b',
+  'src/third_party/instrumented_libs': {
+    'url': Var('chromium_git') + '/chromium/third_party/instrumented_libraries.git' + '@' + '3cc43119a29158bcde39d288a8def4b8ec49baf8',
+    'condition': 'checkout_instrumented_libraries',
+  },
   'src/third_party/libc++/src':
-    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '84fb809dd6dae36d556dc0bb702c6cc2ce9d4b80',
+    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '74dd760826063f15ce4d373b31bc34d1c65e41c2',
   'src/third_party/libc++abi/src':
-    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '8d21803b9076b16d46c32e2f10da191ee758520c',
+    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '7681005c6233e8a21b97e24c1a3c5c6979927d5a',
+  'src/third_party/llvm-libc/src':
+    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libc.git' + '@' + '2019a9e40b0bac10ad29f1a9e2288307b6ef16ce',
+
   'src/third_party/libunwind/src':
-    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'f1c687e0aaf0d70b9a53a150e9be5cb63af9215f',
+    Var('chromium_git') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'd1e95b102f113ded38974cf06a65fe0457b6004b',
   'src/third_party/libjpeg_turbo':
-    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '30bdb85e302ecfc52593636b2f44af438e05e784',
+    Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '927aabfcd26897abb9776ecf2a6c38ea5bb52ab6',
   'src/third_party/nasm':
-    Var('chromium_git') + '/chromium/deps/nasm.git' + '@' + '7fc833e889d1afda72c06220e5bed8fb43b2e5ce',
+    Var('chromium_git') + '/chromium/deps/nasm.git' + '@' + 'f477acb1049f5e043904b87b825c5915084a9a29',
   'src/tools':
-    Var('chromium_git') + '/chromium/src/tools' + '@' + 'a76c0dbb64c603a0d45e0c6dfae3a351b6e1adf1',
+    Var('chromium_git') + '/chromium/src/tools' + '@' + '09973d22d8f4110b35bbf133c613b4df2290d465',
 
   # libyuv-only dependencies (not present in Chromium).
   'src/third_party/gtest-parallel':
@@ -126,87 +141,54 @@
     'condition': 'checkout_android or checkout_linux',
   },
 
+  'src/third_party/re2/src':
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '6dcd83d60f7944926bfd308cc13979fc53dd69ca',
+
   # Android deps:
-  'src/third_party/accessibility_test_framework': {
+  'src/third_party/kotlin_stdlib/cipd': {
       'packages': [
           {
-              'package': 'chromium/third_party/accessibility-test-framework',
-              'version': 'b5ec1e56e58e56bc1a0c77d43111c37f9b512c8a',
+              'package': 'chromium/third_party/kotlin_stdlib',
+              'version': 'uguVAY3NvbfV4KgHrjjwvtTioMwPwSijfAgBPpbaYk0C',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/kotlin_stdlib': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'Z1gsqhL967kFQecxKrRwXHbl-vwQjpv0l7PMUZ0EVO8C',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
   'src/third_party/kotlinc/current': {
       'packages': [
           {
               'package': 'chromium/third_party/kotlinc',
-              'version': 'Rr02Gf2EkaeSs3EhSUHhPqDHSd1AzimrM6cRYUJCPjQC',
+              'version': 'YrBSUjA4zjPf3DhU2SYlqamxAAQiM2WIeZftsDSjqTAC',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/boringssl/src':
-    'https://boringssl.googlesource.com/boringssl.git' + '@' + '20a06474c0b4a16779311bfe98ba69dc2402101d',
-  'src/base': {
-    'url': Var('chromium_git') + '/chromium/src/base' + '@' + 'd407b7061bce341bb6e11b539ea86c46c949ac4c',
-    'condition': 'checkout_android',
-  },
-  'src/third_party/bazel': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/bazel',
-              'version': 'VjMsf48QUWw8n7XtJP2AuSjIGmbQeYdWdwyxVvIRLmAC',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-  'src/third_party/bouncycastle': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/bouncycastle',
-              'version': 'c078e87552ba26e776566fdaf0f22cd8712743d0',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-  'src/third_party/android_toolchain': {
-      'packages': [
-            {
-                'package': 'chromium/third_party/android_toolchain/android_toolchain',
-                'version': 'R_8suM8m0oHbZ1awdxGXvKEFpAOETscbfZxkkMthyk8C',
-            },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/androidx': {
+  'src/third_party/android_toolchain/ndk': {
     'packages': [
       {
-          'package': 'chromium/third_party/androidx',
-          'version': 'y7rF_rx56mD3FGhMiqnlbQ6HOqHJ95xUFNX1m-_a988C',
+        'package': 'chromium/third_party/android_toolchain/android_toolchain',
+        'version': 'Idl-vYnWGnM8K3XJhM3h6zjYVDXlnljVz3FE00V9IM8C',
       },
     ],
     'condition': 'checkout_android',
     'dep_type': 'cipd',
   },
 
+  'src/third_party/androidx/cipd': {
+    'packages': [
+      {
+          'package': 'chromium/third_party/androidx',
+          'version': 'gUjEawxv5mQO8yfbuC8W-rx4V3zYE-4LTWggXpZHI4sC',
+      },
+    ],
+    'condition': 'checkout_android and non_git_source',
+    'dep_type': 'cipd',
+  },
+
   'src/third_party/android_support_test_runner': {
       'packages': [
           {
@@ -219,38 +201,26 @@
   },
   'src/third_party/android_sdk/public': {
       'packages': [
-          {
-              'package': 'chromium/third_party/android_sdk/public/build-tools/34.0.0',
-              'version': 'YK9Rzw3fDzMHVzatNN6VlyoD_81amLZpN1AbmkdOd6AC',
-          },
-          {
+         {
+              'package': 'chromium/third_party/android_sdk/public/build-tools/35.0.0',
+              'version': 'DxwAZ3hD551Neu6ycuW5CPnXFrdleRBd93oX1eB_m9YC'
+         },
+         {
               'package': 'chromium/third_party/android_sdk/public/emulator',
-              'version': '9lGp8nTUCRRWGMnI_96HcKfzjnxEJKUcfvfwmA3wXNkC',
-          },
-          {
-              'package': 'chromium/third_party/android_sdk/public/patcher',
-              'version': 'I6FNMhrXlpB-E1lOhMlvld7xt9lBVNOO83KIluXDyA0C',
-          },
-          {
+              'version': '9lGp8nTUCRRWGMnI_96HcKfzjnxEJKUcfvfwmA3wXNkC'
+         },
+         {
               'package': 'chromium/third_party/android_sdk/public/platform-tools',
-              'version': 'HWVsGs2HCKgSVv41FsOcsfJbNcB0UFiNrF6Tc4yRArYC',
-          },
-          {
-              'package': 'chromium/third_party/android_sdk/public/platforms/android-34',
-              'version': 'u-bhWbTME6u-DjypTgr3ZikCyeAeU6txkR9ET6Uudc8C',
-          },
-   {
-              'package': 'chromium/third_party/android_sdk/public/platforms/android-tiramisuprivacysandbox',
-              'version': 'YWMYkzyxGBgVsty0GhXL1oxbY0pGXQIgFc0Rh7ZMRPYC',
-          },
-          {
-              'package': 'chromium/third_party/android_sdk/public/sources/android-31',
-              'version': '_a_BcnANjPYw5mSKlNHa7GFY8yc1kdqj2rmQgac7yUcC',
-          },
-          {
+              'version': 'WihaseZR6cojZbkzIqwGhpTp92ztaGfqq8njBU8eTXYC'
+         },
+         {
+              'package': 'chromium/third_party/android_sdk/public/platforms/android-35',
+              'version': 'kIXA-9XuCfOESodXEdOBkW5f1ytrGWdbp3HFp1I8A_0C'
+         },
+         {
               'package': 'chromium/third_party/android_sdk/public/cmdline-tools',
-              'version': 'EWnL2r7oV5GtE9Ef7GyohyFam42wtMtEKYU4dCb3U1YC',
-          },
+              'version': 'OCGHZKTdjXjIELVI6FMAgcDkfnd_1ybB0_MtljPtz-8C'
+         }
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
@@ -265,36 +235,19 @@
     'condition': 'checkout_mac',
     'dep_type': 'cipd',
   },
-  'src/third_party/android_build_tools/aapt2': {
+
+
+  'src/third_party/android_build_tools/aapt2/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/android_build_tools/aapt2',
-              'version': 'STY0BXlZxsEhudnlXQFed-B5UpwehcoM0sYqor6qRqsC',
+              'version': '_lNsOL_GGlXLOIMGtrbMOqNd7TQHabaP1q8SlvUpFbMC',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/byte_buddy': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/byte_buddy',
-              'version': 'c9b53316603fc2d997c899c7ca1707f809b918cd',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-  'src/third_party/byte_buddy/android_sdk_build_tools_25_0_2': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_sdk/public/build-tools',
-              'version': 'kwIs2vdfTm93yEP8LG5aSnchN4BVEdVxbqQtF4XpPdkC',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
+
   'src/third_party/ced/src': {
     'url': Var('chromium_git') + '/external/github.com/google/compact_enc_det.git' + '@' + 'ba412eaaacd3186085babcd901679a48863c7dd5',
     'condition': 'checkout_android',
@@ -317,40 +270,34 @@
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/guava': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/guava',
-              'version': 'a6fba501f3a0de88b9be1daa2052632de5b96a46',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-  'src/third_party/hamcrest': {
+
+  'src/third_party/hamcrest/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/hamcrest',
-              'version': '37eccfc658fe79695d6abb6dd497463c4372032f',
+              'version': 'dBioOAmFJjqAr_DY7dipbXdVfAxUQwjOBNibMPtX8lQC',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
 
+
   'src/third_party/icu': {
-    'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'e8c3bc9ea97d4423ad0515e5f1c064f486dae8b1',
+    'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'bbccc2f6efc1b825de5f2c903c48be685cd0cf22',
   },
-  'src/third_party/icu4j': {
+
+  'src/third_party/icu4j/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/icu4j',
-              'version': 'e87e5bed2b4935913ee26a3ebd0b723ee2344354',
+              'version': '8dV7WRVX0tTaNNqkLEnCA_dMofr2MJXFK400E7gOFygC',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
+
   'src/third_party/intellij': {
       'packages': [
           {
@@ -361,14 +308,14 @@
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/jdk': {
+  'src/third_party/jdk/current': {
       'packages': [
           {
               'package': 'chromium/third_party/jdk',
-              'version': 'GCFtf5t6M4HlrHj6NXedHbpHp2xjgognF8ptNci4478C',
+              'version': 'G-WIGWdFIBTPPhv2xPK_lTfI5N7WmfCBh0oTKqX-c5sC',
           },
-      ],
-      'condition': 'checkout_android',
+     ],
+      'condition': 'host_os == "linux" and checkout_android',
       'dep_type': 'cipd',
   },
   'src/third_party/jsr-305/src': {
@@ -376,11 +323,11 @@
     'condition': 'checkout_android',
   },
   'src/third_party/junit/src': {
-    'url': Var('chromium_git') + '/external/junit.git' + '@' + '05fe2a64f59127c02135be22f416e91260d6ede6',
+    'url': Var('chromium_git') + '/external/junit.git' + '@' + '0eb5ce72848d730da5bd6d42902fdd6a8a42055d',
     'condition': 'checkout_android',
   },
   'src/third_party/libunwindstack': {
-      'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '4dbfa0e8c844c8e243b297bc185e54a99ff94f9e',
+      'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '215bddfd8eecb7dd990494854a31b70a96d71b3c',
       'condition': 'checkout_android',
   },
   'src/third_party/ninja': {
@@ -396,16 +343,6 @@
     'url': Var('chromium_git') + '/external/mockito/mockito.git' + '@' + '7c3641bcef717ffa7d765f2c86b847d0aab1aac9',
     'condition': 'checkout_android',
   },
-  'src/third_party/objenesis': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/objenesis',
-              'version': 'tknDblENYi8IaJYyD6tUahUyHYZlzJ_Y74_QZSz4DpIC',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
   'src/third_party/ow2_asm': {
       'packages': [
           {
@@ -416,11 +353,12 @@
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/r8': {
+
+  'src/third_party/r8/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'O1BBWiBTIeNUcraX8STMtQXVaCleu6SJJjWCcnfhPLkC',
+              'version': 'TQJgBofMEzGILWhAM0LXeob_ZpAiDc8w8SBzU0d8o8YC',
           },
       ],
       'condition': 'checkout_android',
@@ -429,11 +367,11 @@
   # This duplication is intentional, so we avoid updating the r8.jar used by
   # dexing unless necessary, since each update invalidates all incremental
   # dexing and unnecessarily slows down all bots.
-  'src/third_party/r8/d8': {
+  'src/third_party/r8/d8/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'vw5kLlW3-suSlCKSO9OQpFWpR8oDnvQ8k1RgKNUapQYC',
+              'version': 'U3Jf_ewWOZyxa6vyO3wjNIgm8XIz1yFk-4k3-wqDL44C',
           },
       ],
       'condition': 'checkout_android',
@@ -453,17 +391,19 @@
     'url': Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'c7e0fc087ceeadb8b4c84a0953a422c474093d6d',
     'condition': 'checkout_android',
   },
-  'src/third_party/robolectric': {
+
+  'src/third_party/robolectric/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/robolectric',
-              'version': 'hzetqh1qFI32FOgQroZvGcGdomrgVBJ6WKRnl1KFw6EC',
+              'version': 'G3VkWqTv1YWDvC6zCrL34iQREzrzdBmSL4GMboAIiAEC',
           },
       ],
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/sqlite4java': {
+
+  'src/third_party/sqlite4java/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/sqlite4java',
@@ -473,11 +413,11 @@
       'condition': 'checkout_android',
       'dep_type': 'cipd',
   },
-  'src/third_party/turbine': {
+  'src/third_party/turbine/cipd': {
       'packages': [
           {
               'package': 'chromium/third_party/turbine',
-              'version': '2I2Nz480QsuCxpQ1lMfbigX8l5HAhX3_ykWU4TKRGo4C',
+              'version': 'dz8pRLjwNlToJ0tS14T-TDQJNikmFXEDByMo-OzBbl0C',
           },
       ],
       'condition': 'checkout_android',
@@ -490,1841 +430,1314 @@
 
   # iOS deps:
   'src/ios': {
-    'url': Var('chromium_git') + '/chromium/src/ios' + '@' + 'ddd58e86cf4ebdc0db60a5d0f3c323de49bb295c',
+    'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '6e4e345fbb2b4f25bb4072d0d0b1cac4ee887126',
     'condition': 'checkout_ios'
   },
 
   # Everything coming after this is automatically updated by the auto-roller.
   # === ANDROID_DEPS Generated Code Start ===
   # Generated by //third_party/android_deps/fetch_all.py
-  'src/third_party/android_deps/libs/android_arch_core_common': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_core_common',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_core_runtime': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_core_runtime',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_common': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_common',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_common_java8': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_common_java8',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_livedata': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_livedata',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_livedata_core': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_livedata_core',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_runtime': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_runtime',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/android_arch_lifecycle_viewmodel': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_viewmodel',
-              'version': 'version:2@1.1.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_animated_vector_drawable': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_animated_vector_drawable',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_appcompat_v7': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_appcompat_v7',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_asynclayoutinflater': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_asynclayoutinflater',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_cardview_v7': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_cardview_v7',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_collections': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_collections',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_coordinatorlayout': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_coordinatorlayout',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_cursoradapter': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_cursoradapter',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_customview': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_customview',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_design': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_design',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_documentfile': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_documentfile',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_drawerlayout': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_drawerlayout',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_interpolator': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_interpolator',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_loader': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_loader',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_localbroadcastmanager': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_localbroadcastmanager',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_multidex': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_multidex',
-              'version': 'version:2@1.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_print': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_print',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_recyclerview_v7': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_recyclerview_v7',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_slidingpanelayout': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_slidingpanelayout',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_android_support_support_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_android_support_support_annotations',
               'version': 'version:2@28.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_android_support_support_compat': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_compat',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_core_ui': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_core_ui',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_core_utils': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_core_utils',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_fragment': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_fragment',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_media_compat': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_media_compat',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_v4': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_v4',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_support_vector_drawable': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_support_vector_drawable',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_swiperefreshlayout': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_swiperefreshlayout',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_transition': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_transition',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_versionedparcelable': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_versionedparcelable',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_support_viewpager': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_android_support_viewpager',
-              'version': 'version:2@28.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_android_tools_common': {
+  'src/third_party/android_deps/cipd/libs/com_android_tools_common': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_android_tools_common',
               'version': 'version:2@30.2.0-beta01.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api': {
+  'src/third_party/android_deps/cipd/libs/com_android_tools_layoutlib_layoutlib_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_android_tools_layoutlib_layoutlib_api',
               'version': 'version:2@30.2.0-beta01.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_android_tools_sdk_common': {
+  'src/third_party/android_deps/cipd/libs/com_android_tools_sdk_common': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_android_tools_sdk_common',
               'version': 'version:2@30.2.0-beta01.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_github_ben_manes_caffeine_caffeine': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_github_ben_manes_caffeine_caffeine',
-              'version': 'version:2@2.8.8.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_github_kevinstern_software_and_algorithms': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_github_kevinstern_software_and_algorithms',
-              'version': 'version:2@1.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_android_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_annotations',
               'version': 'version:2@4.1.1.4.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_apps_common_testing_accessibility_framework_accessibility_test_framework',
               'version': 'version:2@4.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_datatransport_transport_api': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_datatransport_transport_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_datatransport_transport_api',
               'version': 'version:2@2.2.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_auth': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_auth': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth',
-              'version': 'version:2@20.1.0.cr1',
+              'version': 'version:2@21.1.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_auth_api_phone': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone',
-              'version': 'version:2@18.0.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base',
               'version': 'version:2@18.0.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_base': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_auth_base': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base',
+              'version': 'version:2@18.0.10.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_auth_blockstore': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_blockstore',
+              'version': 'version:2@16.4.0.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_base': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_base',
-              'version': 'version:2@18.0.1.cr1',
+              'version': 'version:2@18.5.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_basement': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_basement': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_basement',
-              'version': 'version:2@18.1.0.cr1',
+              'version': 'version:2@18.4.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_cast': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_cast': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_cast_framework': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_clearcut': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_cloud_messaging': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_cloud_messaging': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_cloud_messaging',
               'version': 'version:2@16.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_flags': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_fido': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_fido',
+              'version': 'version:2@21.1.0.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_flags': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_flags',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_gcm': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_gcm': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_gcm',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_iid': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_identity_credentials': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_identity_credentials',
+              'version': 'version:2@16.0.0-alpha02.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_iid': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_iid',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_instantapps': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps',
               'version': 'version:2@18.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_location': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_location': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_location',
-              'version': 'version:2@19.0.1.cr1',
+              'version': 'version:2@21.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_phenotype': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_places_placereport',
-              'version': 'version:2@17.0.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_stats': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_stats': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_stats',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_tasks': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_tasks': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_tasks',
-              'version': 'version:2@18.0.2.cr1',
+              'version': 'version:2@18.2.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_vision': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_vision': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision',
               'version': 'version:2@20.1.3.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_gms_play_services_vision_common': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common',
               'version': 'version:2@19.1.3.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_material_material': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_libraries_identity_googleid_googleid': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_android_libraries_identity_googleid_googleid',
+              'version': 'version:2@1.1.1.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_google_android_material_material': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_material_material',
-              'version': 'version:2@1.7.0-alpha02.cr1',
+              'version': 'version:2@1.13.0-alpha05.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_play_core_common': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_play_core_common': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_play_core_common',
               'version': 'version:2@2.0.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_android_play_feature_delivery': {
+  'src/third_party/android_deps/cipd/libs/com_google_android_play_feature_delivery': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_android_play_feature_delivery',
               'version': 'version:2@2.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_auto_auto_common': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_auto_auto_common',
-              'version': 'version:2@1.2.1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_auto_service_auto_service': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_auto_service_auto_service',
-              'version': 'version:2@1.0-rc6.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_auto_service_auto_service_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_auto_service_auto_service_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_auto_service_auto_service_annotations',
               'version': 'version:2@1.0-rc6.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_auto_value_auto_value_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_auto_value_auto_value_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_auto_value_auto_value_annotations',
-              'version': 'version:2@1.10.1.cr1',
+              'version': 'version:2@1.11.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_code_findbugs_jsr305': {
+  'src/third_party/android_deps/cipd/libs/com_google_code_findbugs_jsr305': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_code_findbugs_jsr305',
               'version': 'version:2@3.0.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_code_gson_gson': {
+  'src/third_party/android_deps/cipd/libs/com_google_code_gson_gson': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_code_gson_gson',
               'version': 'version:2@2.9.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_dagger_dagger': {
+  'src/third_party/android_deps/cipd/libs/com_google_dagger_dagger': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger',
-              'version': 'version:2@2.30.cr1',
+              'version': 'version:2@2.52.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_dagger_dagger_compiler': {
+  'src/third_party/android_deps/cipd/libs/com_google_dagger_hilt_core': {
       'packages': [
           {
-              'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger_compiler',
-              'version': 'version:2@2.30.cr1',
+              'package': 'chromium/third_party/android_deps/libs/com_google_dagger_hilt_core',
+              'version': 'version:2@2.52.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_dagger_dagger_producers': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger_producers',
-              'version': 'version:2@2.30.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_dagger_dagger_spi': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_dagger_dagger_spi',
-              'version': 'version:2@2.30.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_annotation': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_annotation',
-              'version': 'version:2@2.11.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_errorprone_error_prone_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations',
-              'version': 'version:2@2.18.0.cr1',
+              'version': 'version:2@2.30.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_check_api': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_check_api',
-              'version': 'version:2@2.11.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_core': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_core',
-              'version': 'version:2@2.11.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_error_prone_type_annotations': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_error_prone_type_annotations',
-              'version': 'version:2@2.11.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_javac': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_javac',
-              'version': 'version:2@9+181-r4173-1.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_errorprone_javac_shaded': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_errorprone_javac_shaded',
-              'version': 'version:2@9-dev-r4023-3.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_annotations',
               'version': 'version:2@16.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_common': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_common': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_common',
               'version': 'version:2@19.5.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_components': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_components': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_components',
               'version': 'version:2@16.1.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_encoders': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_encoders': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_encoders',
               'version': 'version:2@16.1.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_encoders_json': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json',
               'version': 'version:2@17.1.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_iid': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_iid': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_iid',
               'version': 'version:2@21.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_iid_interop': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_iid_interop': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_iid_interop',
               'version': 'version:2@17.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_installations': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_installations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_installations',
               'version': 'version:2@16.3.5.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_installations_interop': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_installations_interop': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_installations_interop',
               'version': 'version:2@16.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_measurement_connector': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_measurement_connector': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_measurement_connector',
               'version': 'version:2@18.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_firebase_firebase_messaging': {
+  'src/third_party/android_deps/cipd/libs/com_google_firebase_firebase_messaging': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_firebase_firebase_messaging',
               'version': 'version:2@21.0.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format',
-              'version': 'version:2@1.5.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_guava_failureaccess': {
+  'src/third_party/android_deps/cipd/libs/com_google_guava_failureaccess': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_guava_failureaccess',
-              'version': 'version:2@1.0.1.cr1',
+              'version': 'version:2@1.0.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_guava_guava': {
+  'src/third_party/android_deps/cipd/libs/com_google_guava_guava': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_guava_guava',
-              'version': 'version:2@31.1-jre.cr1',
+              'version': 'version:2@33.3.1-jre.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_guava_guava_android': {
+  'src/third_party/android_deps/cipd/libs/com_google_guava_guava_android': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_guava_guava_android',
-              'version': 'version:2@31.1-android.cr1',
+              'version': 'version:2@33.3.1-android.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_guava_listenablefuture': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_guava_listenablefuture',
-              'version': 'version:2@1.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations': {
+  'src/third_party/android_deps/cipd/libs/com_google_j2objc_j2objc_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations',
-              'version': 'version:2@1.3.cr1',
+              'version': 'version:2@3.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_google_protobuf_protobuf_java': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/com_google_protobuf_protobuf_java',
-              'version': 'version:2@3.19.2.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite': {
+  'src/third_party/android_deps/cipd/libs/com_google_protobuf_protobuf_javalite': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite',
-              'version': 'version:2@3.21.1.cr1',
+              'version': 'version:2@4.28.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils': {
+  'src/third_party/android_deps/cipd/libs/com_google_testparameterinjector_test_parameter_injector': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_google_testparameterinjector_test_parameter_injector',
+              'version': 'version:2@1.18.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_googlecode_java_diff_utils_diffutils': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_googlecode_java_diff_utils_diffutils',
               'version': 'version:2@1.3.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_squareup_javapoet': {
+  'src/third_party/android_deps/cipd/libs/com_squareup_javapoet': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_squareup_javapoet',
               'version': 'version:2@1.13.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_squareup_javawriter': {
+  'src/third_party/android_deps/cipd/libs/com_squareup_javawriter': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_squareup_javawriter',
               'version': 'version:2@2.1.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_squareup_okio_okio_jvm': {
+  'src/third_party/android_deps/cipd/libs/com_squareup_moshi_moshi': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_squareup_moshi_moshi',
+              'version': 'version:2@1.15.0.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_squareup_moshi_moshi_adapters': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/com_squareup_moshi_moshi_adapters',
+              'version': 'version:2@1.15.0.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/com_squareup_okio_okio_jvm': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_squareup_okio_okio_jvm',
-              'version': 'version:2@3.3.0.cr1',
+              'version': 'version:2@3.9.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/com_squareup_wire_wire_runtime_jvm': {
+  'src/third_party/android_deps/cipd/libs/com_squareup_wire_wire_runtime_jvm': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/com_squareup_wire_wire_runtime_jvm',
-              'version': 'version:2@4.7.0.cr1',
+              'version': 'version:2@5.0.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_github_java_diff_utils_java_diff_utils': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/io_github_java_diff_utils_java_diff_utils',
-              'version': 'version:2@4.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/io_grpc_grpc_api': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_api',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_grpc_grpc_binder': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_binder': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_binder',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_grpc_grpc_context': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_context': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_context',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_grpc_grpc_core': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_core': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_core',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_grpc_grpc_protobuf_lite': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_protobuf_lite': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_protobuf_lite',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_grpc_grpc_stub': {
+  'src/third_party/android_deps/cipd/libs/io_grpc_grpc_stub': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_grpc_grpc_stub',
               'version': 'version:2@1.49.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/io_perfmark_perfmark_api': {
+  'src/third_party/android_deps/cipd/libs/io_perfmark_perfmark_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/io_perfmark_perfmark_api',
               'version': 'version:2@0.25.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/javax_annotation_javax_annotation_api': {
+  'src/third_party/android_deps/cipd/libs/jakarta_inject_jakarta_inject_api': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/jakarta_inject_jakarta_inject_api',
+              'version': 'version:2@2.0.1.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/javax_annotation_javax_annotation_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/javax_annotation_javax_annotation_api',
               'version': 'version:2@1.3.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/javax_annotation_jsr250_api': {
+  'src/third_party/android_deps/cipd/libs/javax_annotation_jsr250_api': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/javax_annotation_jsr250_api',
               'version': 'version:2@1.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/javax_inject_javax_inject': {
+  'src/third_party/android_deps/cipd/libs/javax_inject_javax_inject': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/javax_inject_javax_inject',
               'version': 'version:2@1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/net_bytebuddy_byte_buddy': {
+  'src/third_party/android_deps/cipd/libs/net_bytebuddy_byte_buddy': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy',
-              'version': 'version:2@1.14.5.cr1',
+              'version': 'version:2@1.14.12.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent': {
+  'src/third_party/android_deps/cipd/libs/net_bytebuddy_byte_buddy_agent': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/net_bytebuddy_byte_buddy_agent',
-              'version': 'version:2@1.14.5.cr1',
+              'version': 'version:2@1.14.12.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/net_ltgt_gradle_incap_incap': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/net_ltgt_gradle_incap_incap',
-              'version': 'version:2@0.2.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/org_bouncycastle_bcprov_jdk18on': {
+  'src/third_party/android_deps/cipd/libs/org_bouncycastle_bcprov_jdk18on': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_bouncycastle_bcprov_jdk18on',
-              'version': 'version:2@1.72.cr1',
+              'version': 'version:2@1.78.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup': {
+  'src/third_party/android_deps/cipd/libs/org_ccil_cowan_tagsoup_tagsoup': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ccil_cowan_tagsoup_tagsoup',
               'version': 'version:2@1.2.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_checkerframework_checker_compat_qual': {
+  'src/third_party/android_deps/cipd/libs/org_checkerframework_checker_compat_qual': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_checkerframework_checker_compat_qual',
               'version': 'version:2@2.5.5.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_checkerframework_checker_qual': {
+  'src/third_party/android_deps/cipd/libs/org_checkerframework_checker_qual': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_checkerframework_checker_qual',
-              'version': 'version:2@3.25.0.cr1',
+              'version': 'version:2@3.43.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_checkerframework_checker_util': {
+  'src/third_party/android_deps/cipd/libs/org_checkerframework_checker_util': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_checkerframework_checker_util',
               'version': 'version:2@3.25.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_checkerframework_dataflow_errorprone': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/org_checkerframework_dataflow_errorprone',
-              'version': 'version:2@3.15.0.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations': {
+  'src/third_party/android_deps/cipd/libs/org_codehaus_mojo_animal_sniffer_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations',
               'version': 'version:2@1.21.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_conscrypt_conscrypt_openjdk_uber': {
+  'src/third_party/android_deps/cipd/libs/org_conscrypt_conscrypt_openjdk_uber': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_conscrypt_conscrypt_openjdk_uber',
               'version': 'version:2@2.5.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_eclipse_jgit_org_eclipse_jgit': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/org_eclipse_jgit_org_eclipse_jgit',
-              'version': 'version:2@4.4.1.201607150455-r.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/org_hamcrest_hamcrest': {
+  'src/third_party/android_deps/cipd/libs/org_hamcrest_hamcrest': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_hamcrest_hamcrest',
               'version': 'version:2@2.2.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk7': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime': {
       'packages': [
           {
-              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk7',
-              'version': 'version:2@1.8.20.cr1',
+              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime',
+              'version': 'version:2@1.9.22.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk8': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime': {
       'packages': [
           {
-              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_stdlib_jdk8',
-              'version': 'version:2@1.8.20.cr1',
+              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime',
+              'version': 'version:2@1.9.22.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_atomicfu_jvm': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm',
+              'version': 'version:2@0.23.2.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android',
-              'version': 'version:2@1.6.4.cr1',
+              'version': 'version:2@1.8.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm',
-              'version': 'version:2@1.6.4.cr1',
+              'version': 'version:2@1.8.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava',
-              'version': 'version:2@1.6.4.cr1',
+              'version': 'version:2@1.8.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_metadata_jvm': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_kotlinx_coroutines_test_jvm': {
       'packages': [
           {
-              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_metadata_jvm',
-              'version': 'version:2@0.1.0.cr1',
+              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_test_jvm',
+              'version': 'version:2@1.7.3.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_jsoup_jsoup': {
+  'src/third_party/android_deps/cipd/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm',
+              'version': 'version:2@1.7.2.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/org_jsoup_jsoup': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_jsoup_jsoup',
               'version': 'version:2@1.15.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_mockito_mockito_android': {
+  'src/third_party/android_deps/cipd/libs/org_jspecify_jspecify': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_jspecify_jspecify',
+              'version': 'version:2@1.0.0.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/org_mockito_mockito_android': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_android',
-              'version': 'version:2@5.4.0.cr1',
+              'version': 'version:2@5.11.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_mockito_mockito_core': {
+  'src/third_party/android_deps/cipd/libs/org_mockito_mockito_core': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_core',
-              'version': 'version:2@5.4.0.cr1',
+              'version': 'version:2@5.11.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_mockito_mockito_subclass': {
+  'src/third_party/android_deps/cipd/libs/org_mockito_mockito_subclass': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_mockito_mockito_subclass',
-              'version': 'version:2@5.4.0.cr1',
+              'version': 'version:2@5.11.0.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_objenesis_objenesis': {
+  'src/third_party/android_deps/cipd/libs/org_objenesis_objenesis': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_objenesis_objenesis',
               'version': 'version:2@3.3.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ow2_asm_asm': {
+  'src/third_party/android_deps/cipd/libs/org_ow2_asm_asm': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ow2_asm_asm',
-              'version': 'version:2@9.5.cr1',
+              'version': 'version:2@9.7.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ow2_asm_asm_analysis': {
+  'src/third_party/android_deps/cipd/libs/org_ow2_asm_asm_analysis': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ow2_asm_asm_analysis',
-              'version': 'version:2@9.5.cr1',
+              'version': 'version:2@9.7.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ow2_asm_asm_commons': {
+  'src/third_party/android_deps/cipd/libs/org_ow2_asm_asm_commons': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ow2_asm_asm_commons',
-              'version': 'version:2@9.5.cr1',
+              'version': 'version:2@9.7.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ow2_asm_asm_tree': {
+  'src/third_party/android_deps/cipd/libs/org_ow2_asm_asm_tree': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ow2_asm_asm_tree',
-              'version': 'version:2@9.5.cr1',
+              'version': 'version:2@9.7.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_ow2_asm_asm_util': {
+  'src/third_party/android_deps/cipd/libs/org_ow2_asm_asm_util': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_ow2_asm_asm_util',
-              'version': 'version:2@9.5.cr1',
+              'version': 'version:2@9.7.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_pcollections_pcollections': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/org_pcollections_pcollections',
-              'version': 'version:2@3.1.4.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/org_robolectric_annotations': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_annotations': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_annotations',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_junit': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_junit': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_junit',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_nativeruntime': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_nativeruntime': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_nativeruntime',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_nativeruntime_dist_compat': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_nativeruntime_dist_compat': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_nativeruntime_dist_compat',
-              'version': 'version:2@1.0.1.cr1',
+              'version': 'version:2@1.0.16.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_pluginapi': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_pluginapi': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_pluginapi',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_plugins_maven_dependency_resolver': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_plugins_maven_dependency_resolver': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_plugins_maven_dependency_resolver',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_resources': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_resources': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_resources',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_robolectric': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_robolectric': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_robolectric',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_sandbox': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_sandbox': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_sandbox',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_shadowapi': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_shadowapi': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadowapi',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_shadows_framework': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_shadows_framework': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_framework',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_shadows_playservices': {
-      'packages': [
-          {
-              'package': 'chromium/third_party/android_deps/libs/org_robolectric_shadows_playservices',
-              'version': 'version:2@4.10.3.cr1',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
-  'src/third_party/android_deps/libs/org_robolectric_utils': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_utils': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
-  'src/third_party/android_deps/libs/org_robolectric_utils_reflector': {
+  'src/third_party/android_deps/cipd/libs/org_robolectric_utils_reflector': {
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/libs/org_robolectric_utils_reflector',
-              'version': 'version:2@4.10.3.cr1',
+              'version': 'version:2@4.14.1.cr1',
           },
       ],
-      'condition': 'checkout_android',
+      'condition': 'checkout_android and non_git_source',
+      'dep_type': 'cipd',
+  },
+
+  'src/third_party/android_deps/cipd/libs/org_yaml_snakeyaml': {
+      'packages': [
+          {
+              'package': 'chromium/third_party/android_deps/libs/org_yaml_snakeyaml',
+              'version': 'version:2@2.3.cr1',
+          },
+      ],
+      'condition': 'checkout_android and non_git_source',
       'dep_type': 'cipd',
   },
 
   # === ANDROID_DEPS Generated Code End ===
 }
 
-pre_deps_hooks = [
-  {
-    # Remove any symlinks from before 177567c518b121731e507e9b9c4049c4dc96e4c8.
-    # TODO(kjellander): Remove this in March 2017.
-    'name': 'cleanup_links',
-    'pattern': '.',
-    'action': ['python3', 'src/cleanup_links.py'],
-  },
-]
-
 hooks = [
   {
     # This clobbers when necessary (based on get_landmines.py). It should be
@@ -2391,54 +1804,6 @@
     'condition': 'checkout_mac',
   },
   {
-    'name': 'msan_chained_origins_focal',
-    'pattern': '.',
-    'condition': 'checkout_instrumented_libraries',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-instrumented-libraries',
-                '-s', 'src/third_party/instrumented_libraries/binaries/msan-chained-origins-focal.tgz.sha1',
-              ],
-  },
-  {
-    'name': 'msan_no_origins_focal',
-    'pattern': '.',
-    'condition': 'checkout_instrumented_libraries',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-instrumented-libraries',
-                '-s', 'src/third_party/instrumented_libraries/binaries/msan-no-origins-focal.tgz.sha1',
-              ],
-  },
-  {
-    'name': 'msan_chained_origins_focal',
-    'pattern': '.',
-    'condition': 'checkout_instrumented_libraries',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-instrumented-libraries',
-                '-s', 'src/third_party/instrumented_libraries/binaries/msan-chained-origins-focal.tgz.sha1',
-              ],
-  },
-  {
-    'name': 'msan_no_origins_focal',
-    'pattern': '.',
-    'condition': 'checkout_instrumented_libraries',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-instrumented-libraries',
-                '-s', 'src/third_party/instrumented_libraries/binaries/msan-no-origins-focal.tgz.sha1',
-              ],
-  },
-  {
     'name': 'Download Fuchsia SDK from GCS',
     'pattern': '.',
     'condition': 'checkout_fuchsia',
@@ -2473,60 +1838,6 @@
     'action': ['python3', 'src/build/util/lastchange.py',
                '-o', 'src/build/util/LASTCHANGE'],
   },
-  # Pull clang-format binaries using checked-in hashes.
-  {
-    'name': 'clang_format_win',
-    'pattern': '.',
-    'condition': 'host_os == "win"',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--platform=win32',
-                '--no_auth',
-                '--bucket', 'chromium-clang-format',
-                '-s', 'src/buildtools/win/clang-format.exe.sha1',
-    ],
-  },
-  {
-    'name': 'clang_format_mac_x64',
-    'pattern': '.',
-    'condition': 'host_os == "mac" and host_cpu == "x64"',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--platform=darwin',
-                '--no_auth',
-                '--bucket', 'chromium-clang-format',
-                '-s', 'src/buildtools/mac/clang-format.x64.sha1',
-                '-o', 'src/buildtools/mac/clang-format',
-    ],
-  },
-  {
-    'name': 'clang_format_mac_arm64',
-    'pattern': '.',
-    'condition': 'host_os == "mac" and host_cpu == "arm64"',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--no_auth',
-                '--bucket', 'chromium-clang-format',
-                '-s', 'src/buildtools/mac/clang-format.arm64.sha1',
-                '-o', 'src/buildtools/mac/clang-format',
-     ],
-  },
-  {
-    'name': 'clang_format_linux',
-    'pattern': '.',
-    'condition': 'host_os == "linux"',
-    'action': [ 'python3',
-                'src/third_party/depot_tools/download_from_google_storage.py',
-                '--no_resume',
-                '--platform=linux*',
-                '--no_auth',
-                '--bucket', 'chromium-clang-format',
-                '-s', 'src/buildtools/linux64/clang-format.sha1',
-    ],
-  },
   # Pull luci-go binaries (isolate, swarming) using checked-in hashes.
   {
     'name': 'luci-go_win',
@@ -2571,6 +1882,25 @@
       'src/testing/location_tags.json',
     ],
   },
+  # Download remote exec cfg files
+  {
+    'name': 'fetch_reclient_cfgs',
+    'pattern': '.',
+    'condition': 'download_remoteexec_cfg',
+    'action': ['python3',
+               'src/buildtools/reclient_cfgs/fetch_reclient_cfgs.py',
+               '--rbe_instance',
+               Var('rbe_instance'),
+               '--reproxy_cfg_template',
+               'reproxy.cfg.template',
+               '--rewrapper_cfg_project',
+               Var('rewrapper_cfg_project'),
+               '--quiet',
+               ],
+  },
 ]
 
-recursedeps = []
+recursedeps = [
+  'src/buildtools',
+  'src/third_party/instrumented_libs',
+]
diff --git a/METADATA b/METADATA
index 19d0436..752e6f5 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,19 @@
 # This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update libyuv
-# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+# Usage: tools/external_updater/updater.sh update external/<absolute path to project>
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
 
 name: "libyuv"
 description: "libyuv is an open source project that includes YUV scaling and conversion functionality."
 third_party {
   license_type: NOTICE
   last_upgrade_date {
-    year: 2024
-    month: 1
-    day: 11
+    year: 2025
+    month: 3
+    day: 25
   }
   identifier {
     type: "Git"
     value: "https://chromium.googlesource.com/libyuv/libyuv/"
-    version: "af6ac8265bbd07bcf977526458b60305c4304288"
+    version: "5f284054cb806f82e737f738003d764277970d45"
   }
 }
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index d3901ca..37df28a 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -9,44 +9,57 @@
 # Runs PRESUBMIT.py in py3 mode by git cl presubmit.
 USE_PYTHON3 = True
 
+
 def _CommonChecks(input_api, output_api):
-  """Checks common to both upload and commit."""
-  results = []
-  results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
-      files_to_skip=(r'^base[\\\/].*\.py$',
-                     r'^build[\\\/].*\.py$',
-                     r'^buildtools[\\\/].*\.py$',
-                     r'^ios[\\\/].*\.py$',
-                     r'^out.*[\\\/].*\.py$',
-                     r'^testing[\\\/].*\.py$',
-                     r'^third_party[\\\/].*\.py$',
-                     r'^tools[\\\/].*\.py$',
-                     # TODO(kjellander): should arguably be checked.
-                     r'^tools_libyuv[\\\/]valgrind[\\\/].*\.py$',
-                     r'^xcodebuild.*[\\\/].*\.py$',),
-      disabled_warnings=['F0401',  # Failed to import x
-                         'E0611',  # No package y in x
-                         'W0232',  # Class has no __init__ method
-                        ],
-      pylintrc='pylintrc',
-      version='2.7'))
-  return results
+    """Checks common to both upload and commit."""
+    results = []
+    results.extend(
+        input_api.canned_checks.RunPylint(
+            input_api,
+            output_api,
+            files_to_skip=(
+                r'^base[\\\/].*\.py$',
+                r'^build[\\\/].*\.py$',
+                r'^buildtools[\\\/].*\.py$',
+                r'^ios[\\\/].*\.py$',
+                r'^out.*[\\\/].*\.py$',
+                r'^testing[\\\/].*\.py$',
+                r'^third_party[\\\/].*\.py$',
+                r'^tools[\\\/].*\.py$',
+                # TODO(kjellander): should arguably be checked.
+                r'^tools_libyuv[\\\/]valgrind[\\\/].*\.py$',
+                r'^xcodebuild.*[\\\/].*\.py$',
+            ),
+            disabled_warnings=[
+                'F0401',  # Failed to import x
+                'E0611',  # No package y in x
+                'W0232',  # Class has no __init__ method
+            ],
+            pylintrc='pylintrc',
+            version='2.7',
+        )
+    )
+    return results
 
 
 def CheckChangeOnUpload(input_api, output_api):
-  results = []
-  results.extend(_CommonChecks(input_api, output_api))
-  results.extend(
-      input_api.canned_checks.CheckGNFormatted(input_api, output_api))
-  return results
+    results = []
+    results.extend(_CommonChecks(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckGNFormatted(input_api, output_api)
+    )
+    return results
 
 
 def CheckChangeOnCommit(input_api, output_api):
-  results = []
-  results.extend(_CommonChecks(input_api, output_api))
-  results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
-  results.extend(input_api.canned_checks.CheckChangeWasUploaded(
-      input_api, output_api))
-  results.extend(input_api.canned_checks.CheckChangeHasDescription(
-      input_api, output_api))
-  return results
+    results = []
+    results.extend(_CommonChecks(input_api, output_api))
+    results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
+    results.extend(
+        input_api.canned_checks.CheckChangeWasUploaded(input_api, output_api)
+    )
+    results.extend(
+        input_api.canned_checks.CheckChangeHasDescription(input_api,
+                                                          output_api)
+    )
+    return results
diff --git a/README.chromium b/README.chromium
index 1389f28..46ed8e3 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,9 +1,10 @@
 Name: libyuv
 URL: https://chromium.googlesource.com/libyuv/libyuv/
-Version: 1883
-License: BSD
+Version: 1907
+License: BSD-3-Clause
 License File: LICENSE
 Shipped: yes
+Security Critical: yes
 
 Description:
 libyuv is an open source project that includes YUV conversion and scaling functionality.
diff --git a/README.md b/README.md
index 95eeb04..4baa69c 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 * Convert to RGB formats for rendering/effects.
 * Rotate by 90/180/270 degrees to adjust for mobile devices in portrait mode.
 * Optimized for SSSE3/AVX2 on x86/x64.
-* Optimized for Neon on Arm.
+* Optimized for Neon/SVE2/SME on Arm.
 * Optimized for MSA on Mips.
 * Optimized for RVV on RISC-V.
 
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index d9d01d5..1613440 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -35,12 +35,13 @@
 
 # Use bundled hermetic Xcode installation maintained by Chromium,
 # except for local iOS builds where it is unsupported.
-if (host_os == "mac") {
+# Allow for mac cross compile on linux machines.
+if (host_os == "mac" || host_os == "linux") {
   _result = exec_script("//build/mac/should_use_hermetic_xcode.py",
                         [ target_os ],
                         "value")
   assert(_result != 2,
-         "Do not allow building targets with the default" +
+         "Do not allow building targets with the default " +
              "hermetic toolchain if the minimum OS version is not met.")
   use_system_xcode = _result == 0
 }
diff --git a/cleanup_links.py b/cleanup_links.py
deleted file mode 100755
index 7d1eba9..0000000
--- a/cleanup_links.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env vpython3
-
-# Copyright 2017 The LibYuv 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.
-
-# This is a copy of the file from WebRTC in:
-# https://chromium.googlesource.com/external/webrtc/+/master/cleanup_links.py
-
-"""Script to cleanup symlinks created from setup_links.py.
-
-Before 177567c518b121731e507e9b9c4049c4dc96e4c8 (#15754) we had a Chromium
-checkout which we created symlinks into. In order to do clean syncs after
-landing that change, this script cleans up any old symlinks, avoiding annoying
-manual cleanup needed in order to complete gclient sync.
-"""
-
-import argparse
-import logging
-import os
-import shelve
-import subprocess
-import sys
-
-
-ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
-LINKS_DB = 'links'
-
-# Version management to make future upgrades/downgrades easier to support.
-SCHEMA_VERSION = 1
-
-class WebRTCLinkSetup():
-  def __init__(self, links_db, dry_run=False):
-    self._dry_run = dry_run
-    self._links_db = links_db
-
-  def CleanupLinks(self):
-    logging.debug('CleanupLinks')
-    for source, link_path  in self._links_db.tems():
-      if source == 'SCHEMA_VERSION':
-        continue
-      if os.path.islink(link_path) or sys.platform.startswith('win'):
-        # os.path.islink() always returns false on Windows
-        # See http://bugs.python.org/issue13143.
-        logging.debug('Removing link to %s at %s', source, link_path)
-        if not self._dry_run:
-          if os.path.exists(link_path):
-            if sys.platform.startswith('win') and os.path.isdir(link_path):
-              subprocess.check_call(['rmdir', '/q', '/s', link_path],
-                                    shell=True)
-            else:
-              os.remove(link_path)
-          del self._links_db[source]
-
-
-def _initialize_database(filename):
-  links_database = shelve.open(filename)
-  # Wipe the database if this version of the script ends up looking at a
-  # newer (future) version of the links db, just to be sure.
-  version = links_database.get('SCHEMA_VERSION')
-  if version and version != SCHEMA_VERSION:
-    logging.info('Found database with schema version %s while this script only '
-                 'supports %s. Wiping previous database contents.', version,
-                 SCHEMA_VERSION)
-    links_database.clear()
-  links_database['SCHEMA_VERSION'] = SCHEMA_VERSION
-  return links_database
-
-
-def main():
-  p = argparse.ArgumentParser()
-  p.add_argument('-d', '--dry-run', action='store_true', default=False,
-                 help='Print what would be done, but don\'t perform any '
-                      'operations. This will automatically set logging to '
-                      'verbose.')
-  p.add_argument('-v', '--verbose', action='store_const',
-                 const=logging.DEBUG, default=logging.INFO,
-                 help='Print verbose output for debugging.')
-  options = p.parse_args()
-
-  if options.dry_run:
-    options.verbose = logging.DEBUG
-  logging.basicConfig(format='%(message)s', level=options.verbose)
-
-  # Work from the root directory of the checkout.
-  script_dir = os.path.dirname(os.path.abspath(__file__))
-  os.chdir(script_dir)
-
-  # The database file gets .db appended on some platforms.
-  db_filenames = [LINKS_DB, LINKS_DB + '.db']
-  if any(os.path.isfile(f) for f in db_filenames):
-    links_database = _initialize_database(LINKS_DB)
-    try:
-      symlink_creator = WebRTCLinkSetup(links_database, options.dry_run)
-      symlink_creator.CleanupLinks()
-    finally:
-      for f in db_filenames:
-        if os.path.isfile(f):
-          os.remove(f)
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/docs/environment_variables.md b/docs/environment_variables.md
index 4eb0965..173c207 100644
--- a/docs/environment_variables.md
+++ b/docs/environment_variables.md
@@ -7,9 +7,11 @@
 By default the cpu is detected and the most advanced form of SIMD is used.  But you can disable instruction sets selectively, or completely, falling back on C code.  Set the variable to 1 to disable the specified instruction set.
 
 ## All CPUs
+
     LIBYUV_DISABLE_ASM
 
 ## Intel CPUs
+
     LIBYUV_DISABLE_X86
     LIBYUV_DISABLE_SSE2
     LIBYUV_DISABLE_SSSE3
@@ -26,21 +28,32 @@
     LIBYUV_DISABLE_AVX512VBMI
     LIBYUV_DISABLE_AVX512VBMI2
     LIBYUV_DISABLE_AVX512VBITALG
-    LIBYUV_DISABLE_AVX512VPOPCNTDQ
-    LIBYUV_DISABLE_GFNI
+    LIBYUV_DISABLE_AVX10
+    LIBYUV_DISABLE_AVX10_2
+    LIBYUV_DISABLE_AVXVNNI
+    LIBYUV_DISABLE_AVXVNNIINT8
+    LIBYUV_DISABLE_AMXINT8
 
-## ARM CPUs
+## Arm CPUs
 
     LIBYUV_DISABLE_NEON
+    LIBYUV_DISABLE_NEON_DOTPROD
+    LIBYUV_DISABLE_NEON_I8MM
+    LIBYUV_DISABLE_SVE
+    LIBYUV_DISABLE_SVE2
+    LIBYUV_DISABLE_SME
 
 ## MIPS CPUs
+
     LIBYUV_DISABLE_MSA
 
 ## LOONGARCH CPUs
+
     LIBYUV_DISABLE_LSX
     LIBYUV_DISABLE_LASX
 
 ## RISCV CPUs
+
     LIBYUV_DISABLE_RVV
 
 # Test Width/Height/Repeat
diff --git a/docs/feature_detection.md b/docs/feature_detection.md
new file mode 100644
index 0000000..d32e84b
--- /dev/null
+++ b/docs/feature_detection.md
@@ -0,0 +1,108 @@
+# Introduction
+
+Several routines in libyuv have multiple implementations specialized for a
+variety of CPU architecture extensions. Libyuv will automatically detect and
+use the latest architecture extension present on a machine for which a kernel
+implementation is available.
+
+# Feature detection on AArch64
+
+## Architecture extensions of interest
+
+The Arm 64-bit A-class architecture has a number of vector extensions which can
+be used to accelerate libyuv kernels.
+
+### Neon extensions
+
+Neon is available and mandatory in AArch64 from the base Armv8.0-A
+architecture. Neon can be used even if later extensions like the Scalable
+Vector Extension (SVE) are also present. The exception to this is if the CPU is
+currently operating in streaming mode as introduced by the Scalable Matrix
+Extension, described later.
+
+There are also a couple of architecture extensions present for Neon that we can
+take advantage of in libyuv:
+
+* The Neon DotProd extension is architecturally available from Armv8.1-A and
+  becomes mandatory from Armv8.4-A. This extension provides instructions to
+  perform a pairwise widening multiply of groups of four bytes from two source
+  vectors, taking the sum of the four widened multiply results within each
+  group to give a 32-bit result, accumulating into a destination vector.
+
+* The Neon I8MM extension extends the DotProd extension with support for
+  mixed-sign DotProds. The I8MM extension is architecturally available from
+  Armv8.1-A and becomes mandatory from Armv8.6-A. It does not strictly depend
+  on the DotProd extension being implemented, however at time of writing there
+  is no known micro-architecture implementation where I8MM is implemented
+  without the DotProd extension also being implemented.
+
+### The Scalable Vector Extension (SVE)
+
+The two Scalable Vector extensions (SVE and SVE2) provides equivalent
+functionality to most existing Neon instructions but with the ability to
+efficiently operate on vector registers with a run-time-determined vector
+length.
+
+The original version of SVE is architecturally available from Armv8.2-A and is
+primarily targeted at HPC applications. This focus means it does not include
+most of the DSP-style operations that are necessary for most libyuv
+color-conversion kernels, though it can still be used for many scaling or
+rotation kernels.
+
+SVE does not strictly depend on either of the Neon DotProd or I8MM extensions
+being implemented. The only micro-architecture at time of writing where SVE is
+implemented without these two extensions both also being implemented is the
+Fujitsu A64FX, which is not a CPU of interest for libyuv.
+
+SVE2 extends the base SVE extension with the remaining instructions from Neon,
+porting these instructions to operate on scalable vectors. SVE2 is
+architecturally available from Armv9.0-A. If SVE2 is implemented then SVE must
+also be implemented. Since Armv9.0-A is based on Armv8.5-A this implies that
+the Neon DotProd extension is also implemented. Interestingly this means that
+the I8MM extension is not mandatory since it only becomes mandatory from
+Armv8.6-A or Armv9.1-A, however there is no micro-architecture at time of
+writing where SVE2 is implemented without all previously-mentioned features
+also being implemented.
+
+### The Scalable Matrix Extension (SME)
+
+The Scalable Matrix Extension (SME) is an optional feature introduced from
+Armv9.2-A. SME exists alongside SVE and introduces new execution modes for
+applications performing extended periods of data processing. In particular SME
+introduces a few new components of interest:
+
+* Access to a scalable two-dimensional ZA tile register and new instructions to
+  interact with rows and columns of the ZA tiles. This can be useful for data
+  transformations like transposes.
+
+* A streaming SVE (SSVE) mode, during which the SVE vector length matches the
+  ZA tile register width. In typical systems where the ZA tile register width
+  is longer than the core SVE vector length, SSVE processing allows for faster
+  data processing, even if the ZA tile register is unused.  While the CPU is
+  executing in streaming mode, Neon instructions are unavailable.
+
+* When both SSVE and the ZA tile registers are enabled there are additional
+  outer-product instructions accumulating into a whole ZA tile, suitable for
+  accelerating matrix arithmetic. This is likely less useful in libyuv.
+
+## Linux and Android
+
+On AArch64 running under Linux and Android, features are detected by inspecting
+the CPU auxiliary vector via `getauxval(AT_HWCAP)` and `getauxval(AT_HWCAP2)`,
+inspecting the returned bitmask.
+
+## Windows
+
+On Windows we detect features using the `IsProcessorFeaturePresent` interface
+and passing an enum parameter for the feature we want to check. More
+information on this can be found here:
+
+    https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent#parameters
+
+## Apple Silicon
+
+On Apple Silicon we detect features using the `sysctlbyname` interface and
+passing a string representing the feature we want to detect. More information
+on this can be found here:
+
+    https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
diff --git a/docs/getting_started.md b/docs/getting_started.md
index f2f71b8..a052727 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -59,13 +59,13 @@
 
 ### Windows
 
-    call gn gen out\Release "--args=is_debug=false target_cpu=\"x64\""
-    call gn gen out\Debug "--args=is_debug=true target_cpu=\"x64\""
+    gn gen out\Release "--args=is_debug=false target_cpu=\"x64\""
+    gn gen out\Debug "--args=is_debug=true target_cpu=\"x64\""
     ninja -v -C out\Release
     ninja -v -C out\Debug
 
-    call gn gen out\Release "--args=is_debug=false target_cpu=\"x86\""
-    call gn gen out\Debug "--args=is_debug=true target_cpu=\"x86\""
+    gn gen out\Release "--args=is_debug=false target_cpu=\"x86\""
+    gn gen out\Debug "--args=is_debug=true target_cpu=\"x86\""
     ninja -v -C out\Release
     ninja -v -C out\Debug
 
diff --git a/download_vs_toolchain.py b/download_vs_toolchain.py
index 6bc086d..9fc89af 100644
--- a/download_vs_toolchain.py
+++ b/download_vs_toolchain.py
@@ -26,4 +26,4 @@
 
 
 if __name__ == '__main__':
-  sys.exit(vs_toolchain.main())
+    sys.exit(vs_toolchain.main())
diff --git a/fuzz/Android.bp b/fuzz/Android.bp
index a8d552b..1df5662 100644
--- a/fuzz/Android.bp
+++ b/fuzz/Android.bp
@@ -1,4 +1,3 @@
-
 package {
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
diff --git a/include/libyuv/compare_row.h b/include/libyuv/compare_row.h
index 8293c91..ec0e331 100644
--- a/include/libyuv/compare_row.h
+++ b/include/libyuv/compare_row.h
@@ -12,45 +12,17 @@
 #define INCLUDE_LIBYUV_COMPARE_ROW_H_
 
 #include "libyuv/basic_types.h"
+#include "libyuv/cpu_support.h"
 
 #ifdef __cplusplus
 namespace libyuv {
 extern "C" {
 #endif
 
-#if defined(__pnacl__) || defined(__CLR_VER) ||            \
-    (defined(__native_client__) && defined(__x86_64__)) || \
-    (defined(__i386__) && !defined(__SSE__) && !defined(__clang__))
-#define LIBYUV_DISABLE_X86
-#endif
-#if defined(__native_client__)
-#define LIBYUV_DISABLE_NEON
-#endif
-// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_NEON)
-#define LIBYUV_DISABLE_NEON
-#endif
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_X86)
-#define LIBYUV_DISABLE_X86
-#endif
-#endif
-// Visual C 2012 required for AVX2.
-#if defined(_M_IX86) && !defined(__clang__) && defined(_MSC_VER) && \
-    _MSC_VER >= 1700
-#define VISUALC_HAS_AVX2 1
-#endif  // VisualStudio >= 2012
-
-// clang >= 3.4.0 required for AVX2.
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
-#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
-#define CLANG_HAS_AVX2 1
-#endif  // clang >= 3.4
-#endif  // __clang__
-
 // The following are available for Visual C and GCC:
-#if !defined(LIBYUV_DISABLE_X86) && \
-    (defined(__x86_64__) || defined(__i386__) || defined(_M_IX86))
+#if !defined(LIBYUV_DISABLE_X86) &&                             \
+    ((defined(__x86_64__) && !defined(LIBYUV_ENABLE_ROWWIN)) || \
+     defined(__i386__) || defined(_M_IX86))
 #define HAS_HASHDJB2_SSE41
 #define HAS_SUMSQUAREERROR_SSE2
 #define HAS_HAMMINGDISTANCE_SSE42
@@ -65,21 +37,32 @@
 #endif
 
 // The following are available for GCC and clangcl:
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 #define HAS_HAMMINGDISTANCE_SSSE3
 #endif
 
 // The following are available for GCC and clangcl:
 #if !defined(LIBYUV_DISABLE_X86) && defined(CLANG_HAS_AVX2) && \
-    (defined(__x86_64__) || defined(__i386__))
+    (defined(__x86_64__) || defined(__i386__)) &&              \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 #define HAS_HAMMINGDISTANCE_AVX2
 #endif
 
 // The following are available for Neon:
 #if !defined(LIBYUV_DISABLE_NEON) && \
     (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__))
-#define HAS_SUMSQUAREERROR_NEON
 #define HAS_HAMMINGDISTANCE_NEON
+#define HAS_SUMSQUAREERROR_NEON
+#endif
+
+// The following are available for AArch64 Neon:
+#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
+#define HAS_HASHDJB2_NEON
+
+#define HAS_HAMMINGDISTANCE_NEON_DOTPROD
+#define HAS_SUMSQUAREERROR_NEON_DOTPROD
 #endif
 
 #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa)
@@ -102,6 +85,9 @@
 uint32_t HammingDistance_NEON(const uint8_t* src_a,
                               const uint8_t* src_b,
                               int count);
+uint32_t HammingDistance_NEON_DotProd(const uint8_t* src_a,
+                                      const uint8_t* src_b,
+                                      int count);
 uint32_t HammingDistance_MSA(const uint8_t* src_a,
                              const uint8_t* src_b,
                              int count);
@@ -117,6 +103,9 @@
 uint32_t SumSquareError_NEON(const uint8_t* src_a,
                              const uint8_t* src_b,
                              int count);
+uint32_t SumSquareError_NEON_DotProd(const uint8_t* src_a,
+                                     const uint8_t* src_b,
+                                     int count);
 uint32_t SumSquareError_MSA(const uint8_t* src_a,
                             const uint8_t* src_b,
                             int count);
@@ -124,6 +113,7 @@
 uint32_t HashDjb2_C(const uint8_t* src, int count, uint32_t seed);
 uint32_t HashDjb2_SSE41(const uint8_t* src, int count, uint32_t seed);
 uint32_t HashDjb2_AVX2(const uint8_t* src, int count, uint32_t seed);
+uint32_t HashDjb2_NEON(const uint8_t* src, int count, uint32_t seed);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/include/libyuv/convert.h b/include/libyuv/convert.h
index 88619a4..750383a 100644
--- a/include/libyuv/convert.h
+++ b/include/libyuv/convert.h
@@ -418,6 +418,20 @@
                int width,
                int height);
 
+// Convert 10 bit P010 to 8 bit NV12.
+// dst_y can be NULL
+LIBYUV_API
+int P010ToNV12(const uint16_t* src_y,
+               int src_stride_y,
+               const uint16_t* src_uv,
+               int src_stride_uv,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_uv,
+               int dst_stride_uv,
+               int width,
+               int height);
+
 #define I412ToI012 I410ToI010
 #define H410ToH010 I410ToI010
 #define H412ToH012 I410ToI010
@@ -511,6 +525,21 @@
                int width,
                int height);
 
+// Convert 10 bit YUV I010 to NV12
+LIBYUV_API
+int I010ToNV12(const uint16_t* src_y,
+               int src_stride_y,
+               const uint16_t* src_u,
+               int src_stride_u,
+               const uint16_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_uv,
+               int dst_stride_uv,
+               int width,
+               int height);
+
 // Convert I210 to P210
 LIBYUV_API
 int I210ToP210(const uint16_t* src_y,
@@ -569,6 +598,23 @@
                int width,
                int height);
 
+// Convert J420 to I420.
+LIBYUV_API
+int J420ToI420(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_u,
+               int dst_stride_u,
+               uint8_t* dst_v,
+               int dst_stride_v,
+               int width,
+               int height);
+
 // Convert I400 (grey) to NV21.
 LIBYUV_API
 int I400ToNV21(const uint8_t* src_y,
@@ -878,6 +924,19 @@
               int width,
               int height);
 
+// RGB big endian (rgb in memory) to I444.
+LIBYUV_API
+int RAWToI444(const uint8_t* src_raw,
+              int src_stride_raw,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_u,
+              int dst_stride_u,
+              uint8_t* dst_v,
+              int dst_stride_v,
+              int width,
+              int height);
+
 // RGB big endian (rgb in memory) to J420.
 LIBYUV_API
 int RAWToJ420(const uint8_t* src_raw,
@@ -891,6 +950,19 @@
               int width,
               int height);
 
+// RGB big endian (rgb in memory) to J444.
+LIBYUV_API
+int RAWToJ444(const uint8_t* src_raw,
+              int src_stride_raw,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_u,
+              int dst_stride_u,
+              uint8_t* dst_v,
+              int dst_stride_v,
+              int width,
+              int height);
+
 // RGB16 (RGBP fourcc) little endian to I420.
 LIBYUV_API
 int RGB565ToI420(const uint8_t* src_rgb565,
diff --git a/include/libyuv/convert_argb.h b/include/libyuv/convert_argb.h
index 35eeac9..5b50567 100644
--- a/include/libyuv/convert_argb.h
+++ b/include/libyuv/convert_argb.h
@@ -1904,6 +1904,26 @@
                       int width,
                       int height);
 
+// Convert YUY2 to ARGB with matrix.
+LIBYUV_API
+int YUY2ToARGBMatrix(const uint8_t* src_yuy2,
+                     int src_stride_yuy2,
+                     uint8_t* dst_argb,
+                     int dst_stride_argb,
+                     const struct YuvConstants* yuvconstants,
+                     int width,
+                     int height);
+
+// Convert UYVY to ARGB with matrix.
+LIBYUV_API
+int UYVYToARGBMatrix(const uint8_t* src_uyvy,
+                     int src_stride_uyvy,
+                     uint8_t* dst_argb,
+                     int dst_stride_argb,
+                     const struct YuvConstants* yuvconstants,
+                     int width,
+                     int height);
+
 // Convert Android420 to ARGB with matrix.
 LIBYUV_API
 int Android420ToARGBMatrix(const uint8_t* src_y,
diff --git a/include/libyuv/convert_from_argb.h b/include/libyuv/convert_from_argb.h
index ff2a581..54b7d99 100644
--- a/include/libyuv/convert_from_argb.h
+++ b/include/libyuv/convert_from_argb.h
@@ -229,6 +229,19 @@
                int width,
                int height);
 
+// Convert ARGB to J444.
+LIBYUV_API
+int ARGBToJ444(const uint8_t* src_argb,
+               int src_stride_argb,
+               uint8_t* dst_yj,
+               int dst_stride_yj,
+               uint8_t* dst_uj,
+               int dst_stride_uj,
+               uint8_t* dst_vj,
+               int dst_stride_vj,
+               int width,
+               int height);
+
 // Convert ARGB to J400. (JPeg full range).
 LIBYUV_API
 int ARGBToJ400(const uint8_t* src_argb,
diff --git a/include/libyuv/cpu_id.h b/include/libyuv/cpu_id.h
index 5a81e7c..44ea8c0 100644
--- a/include/libyuv/cpu_id.h
+++ b/include/libyuv/cpu_id.h
@@ -21,45 +21,52 @@
 // Internal flag to indicate cpuid requires initialization.
 static const int kCpuInitialized = 0x1;
 
-// These flags are only valid on ARM processors.
+// These flags are only valid on Arm processors.
 static const int kCpuHasARM = 0x2;
-static const int kCpuHasNEON = 0x4;
-// 0x8 reserved for future ARM flag.
-
-// These flags are only valid on x86 processors.
-static const int kCpuHasX86 = 0x10;
-static const int kCpuHasSSE2 = 0x20;
-static const int kCpuHasSSSE3 = 0x40;
-static const int kCpuHasSSE41 = 0x80;
-static const int kCpuHasSSE42 = 0x100;
-static const int kCpuHasAVX = 0x200;
-static const int kCpuHasAVX2 = 0x400;
-static const int kCpuHasERMS = 0x800;
-static const int kCpuHasFMA3 = 0x1000;
-static const int kCpuHasF16C = 0x2000;
-static const int kCpuHasAVX512BW = 0x4000;
-static const int kCpuHasAVX512VL = 0x8000;
-static const int kCpuHasAVX512VNNI = 0x10000;
-static const int kCpuHasAVX512VBMI = 0x20000;
-static const int kCpuHasAVX512VBMI2 = 0x40000;
-static const int kCpuHasAVX512VBITALG = 0x80000;
-static const int kCpuHasAVX10 = 0x100000;
-static const int kCpuHasAVXVNNI = 0x200000;
-static const int kCpuHasAVXVNNIINT8 = 0x400000;
-
-// These flags are only valid on MIPS processors.
-static const int kCpuHasMIPS = 0x800000;
-static const int kCpuHasMSA = 0x1000000;
-
-// These flags are only valid on LOONGARCH processors.
-static const int kCpuHasLOONGARCH = 0x2000000;
-static const int kCpuHasLSX = 0x4000000;
-static const int kCpuHasLASX = 0x8000000;
+static const int kCpuHasNEON = 0x100;
+static const int kCpuHasNeonDotProd = 0x200;
+static const int kCpuHasNeonI8MM = 0x400;
+static const int kCpuHasSVE = 0x800;
+static const int kCpuHasSVE2 = 0x1000;
+static const int kCpuHasSME = 0x2000;
 
 // These flags are only valid on RISCV processors.
-static const int kCpuHasRISCV = 0x10000000;
-static const int kCpuHasRVV = 0x20000000;
-static const int kCpuHasRVVZVFH = 0x40000000;
+static const int kCpuHasRISCV = 0x4;
+static const int kCpuHasRVV = 0x100;
+static const int kCpuHasRVVZVFH = 0x200;
+
+// These flags are only valid on x86 processors.
+static const int kCpuHasX86 = 0x8;
+static const int kCpuHasSSE2 = 0x100;
+static const int kCpuHasSSSE3 = 0x200;
+static const int kCpuHasSSE41 = 0x400;
+static const int kCpuHasSSE42 = 0x800;
+static const int kCpuHasAVX = 0x1000;
+static const int kCpuHasAVX2 = 0x2000;
+static const int kCpuHasERMS = 0x4000;
+static const int kCpuHasFSMR = 0x8000;
+static const int kCpuHasFMA3 = 0x10000;
+static const int kCpuHasF16C = 0x20000;
+static const int kCpuHasAVX512BW = 0x40000;
+static const int kCpuHasAVX512VL = 0x80000;
+static const int kCpuHasAVX512VNNI = 0x100000;
+static const int kCpuHasAVX512VBMI = 0x200000;
+static const int kCpuHasAVX512VBMI2 = 0x400000;
+static const int kCpuHasAVX512VBITALG = 0x800000;
+static const int kCpuHasAVX10 = 0x1000000;
+static const int kCpuHasAVX10_2 = 0x2000000;
+static const int kCpuHasAVXVNNI = 0x4000000;
+static const int kCpuHasAVXVNNIINT8 = 0x8000000;
+static const int kCpuHasAMXINT8 = 0x10000000;
+
+// These flags are only valid on MIPS processors.
+static const int kCpuHasMIPS = 0x10;
+static const int kCpuHasMSA = 0x100;
+
+// These flags are only valid on LOONGARCH processors.
+static const int kCpuHasLOONGARCH = 0x20;
+static const int kCpuHasLSX = 0x100;
+static const int kCpuHasLASX = 0x200;
 
 // Optional init function. TestCpuFlag does an auto-init.
 // Returns cpu_info flags.
@@ -87,6 +94,15 @@
 LIBYUV_API
 int RiscvCpuCaps(const char* cpuinfo_name);
 
+#ifdef __linux__
+// On Linux, parse AArch64 features from getauxval(AT_HWCAP{,2}).
+LIBYUV_API
+int AArch64CpuCaps(unsigned long hwcap, unsigned long hwcap2);
+#else
+LIBYUV_API
+int AArch64CpuCaps();
+#endif
+
 // For testing, allow CPU flags to be disabled.
 // ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3.
 // MaskCpuFlags(-1) to enable all cpu specific optimizations.
diff --git a/include/libyuv/cpu_support.h b/include/libyuv/cpu_support.h
new file mode 100644
index 0000000..9304ab2
--- /dev/null
+++ b/include/libyuv/cpu_support.h
@@ -0,0 +1,91 @@
+/*
+ *  Copyright 2024 The LibYuv Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS. All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef INCLUDE_LIBYUV_CPU_SUPPORT_H_
+#define INCLUDE_LIBYUV_CPU_SUPPORT_H_
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if defined(__pnacl__) || defined(__CLR_VER) ||            \
+    (defined(__native_client__) && defined(__x86_64__)) || \
+    (defined(__i386__) && !defined(__SSE__) && !defined(__clang__))
+#define LIBYUV_DISABLE_X86
+#endif
+
+#if defined(__native_client__)
+#define LIBYUV_DISABLE_NEON
+#endif
+
+// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_NEON)
+#define LIBYUV_DISABLE_NEON
+#endif
+#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_X86)
+#define LIBYUV_DISABLE_X86
+#endif
+#endif
+
+// clang >= 3.5.0 required for Arm64.
+#if defined(__clang__) && defined(__aarch64__) && !defined(LIBYUV_DISABLE_NEON)
+#if (__clang_major__ < 3) || (__clang_major__ == 3 && (__clang_minor__ < 5))
+#define LIBYUV_DISABLE_NEON
+#endif  // clang >= 3.5
+#endif  // __clang__
+
+// GCC >= 4.7.0 required for AVX2.
+#if defined(__GNUC__) && !defined(LIBYUV_ENABLE_ROWWIN) && \
+    (defined(__x86_64__) || defined(__i386__))
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
+#define GCC_HAS_AVX2 1
+#endif  // GNUC >= 4.7
+#endif  // __GNUC__
+
+// clang >= 3.4.0 required for AVX2.
+#if defined(__clang__) && !defined(LIBYUV_ENABLE_ROWWIN) && \
+    (defined(__x86_64__) || defined(__i386__))
+#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
+#define CLANG_HAS_AVX2 1
+#endif  // clang >= 3.4
+#endif  // __clang__
+
+// clang >= 6.0.0 required for AVX512.
+#if defined(__clang__) && !defined(LIBYUV_ENABLE_ROWWIN) && \
+    (defined(__x86_64__) || defined(__i386__))
+// clang in xcode follows a different versioning scheme.
+// TODO(fbarchard): fix xcode 9 ios b/789.
+#if (__clang_major__ >= 7) && !defined(__APPLE__)
+#define CLANG_HAS_AVX512 1
+#endif  // clang >= 7
+#endif  // __clang__
+
+// Visual C 2012 required for AVX2.
+#if defined(_M_IX86) &&                                       \
+    (!defined(__clang__) || defined(LIBYUV_ENABLE_ROWWIN)) && \
+    defined(_MSC_VER) && _MSC_VER >= 1700
+#define VISUALC_HAS_AVX2 1
+#endif  // VisualStudio >= 2012
+
+// Clang 19 required for SME due to needing __arm_tpidr2_save from compiler-rt,
+// only enabled on Linux and Android (both define __linux__) for now.
+#if !defined(LIBYUV_DISABLE_SME) && defined(__aarch64__) && \
+    defined(__linux__) && defined(__clang__) && (__clang_major__ >= 19)
+#define CLANG_HAS_SME 1
+#endif
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
+
+#endif  // INCLUDE_LIBYUV_CPU_SUPPORT_H_
diff --git a/include/libyuv/macros_msa.h b/include/libyuv/macros_msa.h
index b9a44fc..6434a4d 100644
--- a/include/libyuv/macros_msa.h
+++ b/include/libyuv/macros_msa.h
@@ -20,9 +20,9 @@
   ({                                                   \
     const uint8_t* psrc_lw_m = (const uint8_t*)(psrc); \
     uint32_t val_m;                                    \
-    asm volatile("lw  %[val_m],  %[psrc_lw_m]  \n"     \
-                 : [val_m] "=r"(val_m)                 \
-                 : [psrc_lw_m] "m"(*psrc_lw_m));       \
+    asm("lw  %[val_m],  %[psrc_lw_m]  \n"              \
+        : [val_m] "=r"(val_m)                          \
+        : [psrc_lw_m] "m"(*psrc_lw_m));                \
     val_m;                                             \
   })
 
@@ -31,9 +31,9 @@
   ({                                                   \
     const uint8_t* psrc_ld_m = (const uint8_t*)(psrc); \
     uint64_t val_m = 0;                                \
-    asm volatile("ld  %[val_m],  %[psrc_ld_m]  \n"     \
-                 : [val_m] "=r"(val_m)                 \
-                 : [psrc_ld_m] "m"(*psrc_ld_m));       \
+    asm("ld  %[val_m],  %[psrc_ld_m]  \n"              \
+        : [val_m] "=r"(val_m)                          \
+        : [psrc_ld_m] "m"(*psrc_ld_m));                \
     val_m;                                             \
   })
 #else  // !(__mips == 64)
@@ -55,9 +55,9 @@
   ({                                                    \
     uint8_t* pdst_sw_m = (uint8_t*)(pdst); /* NOLINT */ \
     uint32_t val_m = (val);                             \
-    asm volatile("sw  %[val_m],  %[pdst_sw_m]  \n"      \
-                 : [pdst_sw_m] "=m"(*pdst_sw_m)         \
-                 : [val_m] "r"(val_m));                 \
+    asm("sw  %[val_m],  %[pdst_sw_m]  \n"               \
+        : [pdst_sw_m] "=m"(*pdst_sw_m)                  \
+        : [val_m] "r"(val_m));                          \
   })
 
 #if (__mips == 64)
@@ -65,9 +65,9 @@
   ({                                                    \
     uint8_t* pdst_sd_m = (uint8_t*)(pdst); /* NOLINT */ \
     uint64_t val_m = (val);                             \
-    asm volatile("sd  %[val_m],  %[pdst_sd_m]  \n"      \
-                 : [pdst_sd_m] "=m"(*pdst_sd_m)         \
-                 : [val_m] "r"(val_m));                 \
+    asm("sd  %[val_m],  %[pdst_sd_m]  \n"               \
+        : [pdst_sd_m] "=m"(*pdst_sd_m)                  \
+        : [val_m] "r"(val_m));                          \
   })
 #else  // !(__mips == 64)
 #define SD(val, pdst)                                        \
@@ -86,8 +86,7 @@
     uint8_t* psrc_lw_m = (uint8_t*)(psrc);      \
     uint32_t val_lw_m;                          \
                                                 \
-    __asm__ volatile(                           \
-        "lwr %[val_lw_m], 0(%[psrc_lw_m]) \n\t" \
+    asm("lwr %[val_lw_m], 0(%[psrc_lw_m]) \n\t" \
         "lwl %[val_lw_m], 3(%[psrc_lw_m]) \n\t" \
                                                 \
         : [val_lw_m] "=&r"(val_lw_m)            \
@@ -102,8 +101,7 @@
     uint8_t* psrc_ld_m = (uint8_t*)(psrc);      \
     uint64_t val_ld_m = 0;                      \
                                                 \
-    __asm__ volatile(                           \
-        "ldr %[val_ld_m], 0(%[psrc_ld_m]) \n\t" \
+    asm("ldr %[val_ld_m], 0(%[psrc_ld_m]) \n\t" \
         "ldl %[val_ld_m], 7(%[psrc_ld_m]) \n\t" \
                                                 \
         : [val_ld_m] "=&r"(val_ld_m)            \
@@ -130,9 +128,9 @@
   ({                                                    \
     uint8_t* pdst_sw_m = (uint8_t*)(pdst); /* NOLINT */ \
     uint32_t val_m = (val);                             \
-    asm volatile("usw  %[val_m],  %[pdst_sw_m]  \n"     \
-                 : [pdst_sw_m] "=m"(*pdst_sw_m)         \
-                 : [val_m] "r"(val_m));                 \
+    asm("usw  %[val_m],  %[pdst_sw_m]  \n"              \
+        : [pdst_sw_m] "=m"(*pdst_sw_m)                  \
+        : [val_m] "r"(val_m));                          \
   })
 
 #define SD(val, pdst)                                        \
diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h
index f934472..dbf51de 100644
--- a/include/libyuv/planar_functions.h
+++ b/include/libyuv/planar_functions.h
@@ -38,8 +38,10 @@
 #endif
 #endif
 // The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
-    (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&                             \
+    (defined(_M_IX86) ||                                        \
+     (defined(__x86_64__) && !defined(LIBYUV_ENABLE_ROWWIN)) || \
+     defined(__i386__))
 #define HAS_ARGBAFFINEROW_SSE2
 #endif
 
@@ -78,6 +80,16 @@
                        int width,
                        int height);
 
+LIBYUV_API
+void Convert8To8Plane(const uint8_t* src_y,
+                      int src_stride_y,
+                      uint8_t* dst_y,
+                      int dst_stride_y,
+                      int scale,  // 220 for Y, 225 for U,V
+                      int bias,   // 16
+                      int width,
+                      int height);
+
 // Set a plane of data to a 32 bit value.
 LIBYUV_API
 void SetPlane(uint8_t* dst_y,
@@ -766,6 +778,10 @@
 
 // Convert plane of 16 bit shorts to half floats.
 // Source values are multiplied by scale before storing as half float.
+//
+// Note: Unlike other libyuv functions that operate on uint16_t buffers, the
+// src_stride_y and dst_stride_y parameters of HalfFloatPlane() are in bytes,
+// not in units of uint16_t.
 LIBYUV_API
 int HalfFloatPlane(const uint16_t* src_y,
                    int src_stride_y,
diff --git a/include/libyuv/rotate_row.h b/include/libyuv/rotate_row.h
index 3e6a2fe..c00d83c 100644
--- a/include/libyuv/rotate_row.h
+++ b/include/libyuv/rotate_row.h
@@ -12,30 +12,15 @@
 #define INCLUDE_LIBYUV_ROTATE_ROW_H_
 
 #include "libyuv/basic_types.h"
+#include "libyuv/cpu_support.h"
 
 #ifdef __cplusplus
 namespace libyuv {
 extern "C" {
 #endif
 
-#if defined(__pnacl__) || defined(__CLR_VER) ||            \
-    (defined(__native_client__) && defined(__x86_64__)) || \
-    (defined(__i386__) && !defined(__SSE__) && !defined(__clang__))
-#define LIBYUV_DISABLE_X86
-#endif
-#if defined(__native_client__)
-#define LIBYUV_DISABLE_NEON
-#endif
-// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_NEON)
-#define LIBYUV_DISABLE_NEON
-#endif
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_X86)
-#define LIBYUV_DISABLE_X86
-#endif
-#endif
 // The following are available for Visual C 32 bit:
+// TODO - port to clangcl on rotate_win
 #if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER) && \
     !defined(__clang__)
 #define HAS_TRANSPOSEWX8_SSSE3
@@ -43,25 +28,38 @@
 #endif
 
 // The following are available for GCC 32 or 64 bit:
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__i386__) || defined(__x86_64__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__i386__) || defined(__x86_64__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 #define HAS_TRANSPOSEWX8_SSSE3
 #define HAS_TRANSPOSE4X4_32_SSE2
 #define HAS_TRANSPOSE4X4_32_AVX2
 #endif
 
 // The following are available for 64 bit GCC:
-#if !defined(LIBYUV_DISABLE_X86) && defined(__x86_64__)
+#if !defined(LIBYUV_DISABLE_X86) && defined(__x86_64__) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 #define HAS_TRANSPOSEWX8_FAST_SSSE3
 #define HAS_TRANSPOSEUVWX8_SSE2
 #endif
 
 #if !defined(LIBYUV_DISABLE_NEON) && \
     (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__))
+#if defined(__aarch64__)
+#define HAS_TRANSPOSEWX16_NEON
+#else
 #define HAS_TRANSPOSEWX8_NEON
+#endif
 #define HAS_TRANSPOSEUVWX8_NEON
 #define HAS_TRANSPOSE4X4_32_NEON
 #endif
 
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+#define HAS_TRANSPOSEWXH_SME
+#define HAS_TRANSPOSEUVWXH_SME
+#endif
+
 #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa)
 #define HAS_TRANSPOSEWX16_MSA
 #define HAS_TRANSPOSEUVWX16_MSA
@@ -94,6 +92,17 @@
                        uint8_t* dst,
                        int dst_stride,
                        int width);
+void TransposeWx16_NEON(const uint8_t* src,
+                        int src_stride,
+                        uint8_t* dst,
+                        int dst_stride,
+                        int width);
+void TransposeWxH_SME(const uint8_t* src,
+                      int src_stride,
+                      uint8_t* dst,
+                      int dst_stride,
+                      int width,
+                      int height);
 void TransposeWx8_SSSE3(const uint8_t* src,
                         int src_stride,
                         uint8_t* dst,
@@ -120,6 +129,11 @@
                            uint8_t* dst,
                            int dst_stride,
                            int width);
+void TransposeWx16_Any_NEON(const uint8_t* src,
+                            int src_stride,
+                            uint8_t* dst,
+                            int dst_stride,
+                            int width);
 void TransposeWx8_Any_SSSE3(const uint8_t* src,
                             int src_stride,
                             uint8_t* dst,
@@ -178,6 +192,14 @@
                          uint8_t* dst_b,
                          int dst_stride_b,
                          int width);
+void TransposeUVWxH_SME(const uint8_t* src,
+                        int src_stride,
+                        uint8_t* dst_a,
+                        int dst_stride_a,
+                        uint8_t* dst_b,
+                        int dst_stride_b,
+                        int width,
+                        int height);
 void TransposeUVWx16_MSA(const uint8_t* src,
                          int src_stride,
                          uint8_t* dst_a,
diff --git a/include/libyuv/row.h b/include/libyuv/row.h
index 46685a5..6e8f46f 100644
--- a/include/libyuv/row.h
+++ b/include/libyuv/row.h
@@ -15,70 +15,19 @@
 #include <stdlib.h>  // For malloc
 
 #include "libyuv/basic_types.h"
+#include "libyuv/cpu_support.h"
 
 #ifdef __cplusplus
 namespace libyuv {
 extern "C" {
 #endif
 
-#if defined(__pnacl__) || defined(__CLR_VER) ||            \
-    (defined(__native_client__) && defined(__x86_64__)) || \
-    (defined(__i386__) && !defined(__SSE__) && !defined(__clang__))
-#define LIBYUV_DISABLE_X86
-#endif
-#if defined(__native_client__)
-#define LIBYUV_DISABLE_NEON
-#endif
-// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_NEON)
-#define LIBYUV_DISABLE_NEON
-#endif
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_X86)
-#define LIBYUV_DISABLE_X86
-#endif
-#endif
-// clang >= 3.5.0 required for Arm64.
-#if defined(__clang__) && defined(__aarch64__) && !defined(LIBYUV_DISABLE_NEON)
-#if (__clang_major__ < 3) || (__clang_major__ == 3 && (__clang_minor__ < 5))
-#define LIBYUV_DISABLE_NEON
-#endif  // clang >= 3.5
-#endif  // __clang__
-
-// GCC >= 4.7.0 required for AVX2.
-#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
-#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
-#define GCC_HAS_AVX2 1
-#endif  // GNUC >= 4.7
-#endif  // __GNUC__
-
-// clang >= 3.4.0 required for AVX2.
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
-#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
-#define CLANG_HAS_AVX2 1
-#endif  // clang >= 3.4
-#endif  // __clang__
-
-// clang >= 6.0.0 required for AVX512.
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
-// clang in xcode follows a different versioning scheme.
-// TODO(fbarchard): fix xcode 9 ios b/789.
-#if (__clang_major__ >= 7) && !defined(__APPLE__)
-#define CLANG_HAS_AVX512 1
-#endif  // clang >= 7
-#endif  // __clang__
-
-// Visual C 2012 required for AVX2.
-#if defined(_M_IX86) && !defined(__clang__) && defined(_MSC_VER) && \
-    _MSC_VER >= 1700
-#define VISUALC_HAS_AVX2 1
-#endif  // VisualStudio >= 2012
-
 // The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
-    (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&                             \
+    (defined(_M_IX86) ||                                        \
+     (defined(__x86_64__) && !defined(LIBYUV_ENABLE_ROWWIN)) || \
+     defined(__i386__))
 // Conversions:
-#define HAS_ABGRTOYROW_SSSE3
 #define HAS_ARGB1555TOARGBROW_SSE2
 #define HAS_ARGB4444TOARGBROW_SSE2
 #define HAS_ARGBEXTRACTALPHAROW_SSE2
@@ -90,9 +39,6 @@
 #define HAS_ARGBTORGB24ROW_SSSE3
 #define HAS_ARGBTORGB565DITHERROW_SSE2
 #define HAS_ARGBTORGB565ROW_SSE2
-#define HAS_ARGBTOYJROW_SSSE3
-#define HAS_ARGBTOYROW_SSSE3
-#define HAS_BGRATOYROW_SSSE3
 #define HAS_COPYROW_ERMS
 #define HAS_COPYROW_SSE2
 #define HAS_H422TOARGBROW_SSSE3
@@ -120,13 +66,8 @@
 #define HAS_NV21TORGB24ROW_SSSE3
 #define HAS_RAWTOARGBROW_SSSE3
 #define HAS_RAWTORGB24ROW_SSSE3
-#define HAS_RAWTOYJROW_SSSE3
-#define HAS_RAWTOYROW_SSSE3
 #define HAS_RGB24TOARGBROW_SSSE3
-#define HAS_RGB24TOYJROW_SSSE3
-#define HAS_RGB24TOYROW_SSSE3
 #define HAS_RGB565TOARGBROW_SSE2
-#define HAS_RGBATOYROW_SSSE3
 #define HAS_SETROW_ERMS
 #define HAS_SETROW_X86
 #define HAS_SPLITUVROW_SSE2
@@ -140,8 +81,6 @@
 #define HAS_YUY2TOYROW_SSE2
 #if !defined(LIBYUV_BIT_EXACT)
 #define HAS_ABGRTOUVROW_SSSE3
-#define HAS_ARGBTOUV444ROW_SSSE3
-#define HAS_ARGBTOUVJROW_SSSE3
 #define HAS_ARGBTOUVROW_SSSE3
 #define HAS_BGRATOUVROW_SSSE3
 #define HAS_RGBATOUVROW_SSSE3
@@ -158,7 +97,8 @@
 #define HAS_ARGBGRAYROW_SSSE3
 #define HAS_ARGBLUMACOLORTABLEROW_SSSE3
 #define HAS_ARGBMIRRORROW_SSE2
-#define HAS_ARGBMULTIPLYROW_SSE2
+// TODO: Re-enable once rounding behaviour is fixed.
+// #define HAS_ARGBMULTIPLYROW_SSE2
 #define HAS_ARGBPOLYNOMIALROW_SSE2
 #define HAS_ARGBQUANTIZEROW_SSE2
 #define HAS_ARGBSEPIAROW_SSSE3
@@ -176,13 +116,24 @@
 
 // The following functions fail on gcc/clang 32 bit with fpic and framepointer.
 // caveat: clangcl uses row_win.cc which works.
-#if defined(__x86_64__) || !defined(__pic__) || defined(__clang__) || \
-    defined(_MSC_VER)
+#if (defined(__x86_64__) || !defined(__pic__) || defined(__clang__) || \
+     defined(_MSC_VER)) &&                                             \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 // TODO(fbarchard): fix build error on android_full_debug=1
 // https://code.google.com/p/libyuv/issues/detail?id=517
 #define HAS_I422ALPHATOARGBROW_SSSE3
 #define HAS_I444ALPHATOARGBROW_SSSE3
 #endif
+#if (defined(__x86_64__) || !defined(__pic__) || defined(__clang__) || \
+     defined(_MSC_VER)) &&                                             \
+    !defined(LIBYUV_ENABLE_ROWWIN)
+// TODO(fbarchard): fix build error on android_full_debug=1
+// https://code.google.com/p/libyuv/issues/detail?id=517
+// TODO(fbarchard): fix LIBYUV_ENABLE_ROWWIN with clang
+#define HAS_I422ALPHATOARGBROW_AVX2
+#define HAS_I444ALPHATOARGBROW_AVX2
+#endif
+
 #endif
 
 // The following are available on all x86 platforms, but
@@ -197,8 +148,6 @@
 #define HAS_ARGBPOLYNOMIALROW_AVX2
 #define HAS_ARGBSHUFFLEROW_AVX2
 #define HAS_ARGBTORGB565DITHERROW_AVX2
-#define HAS_ARGBTOYJROW_AVX2
-#define HAS_ARGBTOYROW_AVX2
 #define HAS_COPYROW_AVX
 #define HAS_H422TOARGBROW_AVX2
 #define HAS_HALFFLOATROW_AVX2
@@ -219,8 +168,6 @@
 #define HAS_NV12TORGB565ROW_AVX2
 #define HAS_NV21TOARGBROW_AVX2
 #define HAS_NV21TORGB24ROW_AVX2
-#define HAS_RAWTOYJROW_AVX2
-#define HAS_RGB24TOYJROW_AVX2
 #define HAS_SPLITUVROW_AVX2
 #define HAS_UYVYTOARGBROW_AVX2
 #define HAS_UYVYTOUV422ROW_AVX2
@@ -231,24 +178,13 @@
 #define HAS_YUY2TOUVROW_AVX2
 #define HAS_YUY2TOYROW_AVX2
 //  #define HAS_HALFFLOATROW_F16C  // Enable to test half float cast
-#if !defined(LIBYUV_BIT_EXACT)
-#define HAS_ARGBTOUVJROW_AVX2
-#define HAS_ARGBTOUVROW_AVX2
-#endif
 
 // Effects:
 #define HAS_ARGBADDROW_AVX2
-#define HAS_ARGBMULTIPLYROW_AVX2
+// TODO: Re-enable once rounding behaviour is fixed.
+// #define HAS_ARGBMULTIPLYROW_AVX2
 #define HAS_ARGBSUBTRACTROW_AVX2
 #define HAS_BLENDPLANEROW_AVX2
-
-#if defined(__x86_64__) || !defined(__pic__) || defined(__clang__) || \
-    defined(_MSC_VER)
-// TODO(fbarchard): fix build error on android_full_debug=1
-// https://code.google.com/p/libyuv/issues/detail?id=517
-#define HAS_I422ALPHATOARGBROW_AVX2
-#define HAS_I444ALPHATOARGBROW_AVX2
-#endif
 #endif
 
 // The following are available for AVX2 Visual C 32 bit:
@@ -275,7 +211,10 @@
 
 // The following are available for gcc/clang x86 platforms:
 // TODO(fbarchard): Port to Visual C
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
+#define HAS_RAWTOYJROW_SSSE3
 #define HAS_AB64TOARGBROW_SSSE3
 #define HAS_ABGRTOAR30ROW_SSSE3
 #define HAS_ABGRTOYJROW_SSSE3
@@ -284,6 +223,8 @@
 #define HAS_ARGBTOAB64ROW_SSSE3
 #define HAS_ARGBTOAR30ROW_SSSE3
 #define HAS_ARGBTOAR64ROW_SSSE3
+#define HAS_ARGBTOUV444ROW_SSSE3
+#define HAS_ARGBTOUVJ444ROW_SSSE3
 #define HAS_ARGBUNATTENUATEROW_SSE2
 #define HAS_CONVERT16TO8ROW_SSSE3
 #define HAS_CONVERT8TO16ROW_SSE2
@@ -309,18 +250,32 @@
 #define HAS_P210TOARGBROW_SSSE3
 #define HAS_P410TOAR30ROW_SSSE3
 #define HAS_P410TOARGBROW_SSSE3
+#define HAS_RAWTOARGBROW_AVX2
 #define HAS_RAWTORGBAROW_SSSE3
 #define HAS_RGB24MIRRORROW_SSSE3
 #define HAS_RGBATOYJROW_SSSE3
 #define HAS_SPLITARGBROW_SSE2
 #define HAS_SPLITARGBROW_SSSE3
+#define HAS_SPLITRGBROW_SSE41
 #define HAS_SPLITRGBROW_SSSE3
 #define HAS_SPLITXRGBROW_SSE2
 #define HAS_SPLITXRGBROW_SSSE3
 #define HAS_SWAPUVROW_SSSE3
 #define HAS_YUY2TONVUVROW_SSE2
+// TODO: port row_win to use 8 bit coefficients.
+#define HAS_ARGBTOYJROW_SSSE3
+#define HAS_ARGBTOYROW_SSSE3
+#define HAS_BGRATOYROW_SSSE3
+#define HAS_RAWTOYROW_SSSE3
+#define HAS_ABGRTOYROW_SSSE3
+#define HAS_RGB24TOYJROW_SSSE3
+#define HAS_RGB24TOYROW_SSSE3
+#define HAS_RGBATOYROW_SSSE3
+
 #if !defined(LIBYUV_BIT_EXACT)
+// TODO: adjust row_win to use 8 bit negative coefficients.
 #define HAS_ABGRTOUVJROW_SSSE3
+#define HAS_ARGBTOUVJROW_SSSE3
 #endif
 
 #if defined(__x86_64__) || !defined(__pic__)
@@ -333,9 +288,15 @@
 
 // The following are available for AVX2 gcc/clang x86 platforms:
 // TODO(fbarchard): Port to Visual C
-#if !defined(LIBYUV_DISABLE_X86) &&               \
-    (defined(__x86_64__) || defined(__i386__)) && \
-    (defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2))
+#if !defined(LIBYUV_DISABLE_X86) &&                       \
+    (defined(__x86_64__) || defined(__i386__)) &&         \
+    (defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
+#define HAS_RAWTOYJROW_AVX2
+#define HAS_RGB24TOYJROW_AVX2
+
+#define HAS_ARGBTOYJROW_AVX2
+#define HAS_ARGBTOYROW_AVX2
 #define HAS_AB64TOARGBROW_AVX2
 #define HAS_ABGRTOAR30ROW_AVX2
 #define HAS_ABGRTOYJROW_AVX2
@@ -347,9 +308,12 @@
 #define HAS_ARGBTOAR64ROW_AVX2
 #define HAS_ARGBTORAWROW_AVX2
 #define HAS_ARGBTORGB24ROW_AVX2
+#define HAS_ARGBTOUV444ROW_AVX2
+#define HAS_ARGBTOUVJ444ROW_AVX2
 #define HAS_ARGBUNATTENUATEROW_AVX2
 #define HAS_CONVERT16TO8ROW_AVX2
 #define HAS_CONVERT8TO16ROW_AVX2
+#define HAS_CONVERT8TO8ROW_AVX2
 #define HAS_DETILEROW_16_AVX
 #define HAS_DIVIDEROW_16_AVX2
 #define HAS_HALFMERGEUVROW_AVX2
@@ -381,6 +345,7 @@
 #define HAS_P410TOARGBROW_AVX2
 #define HAS_RGBATOYJROW_AVX2
 #define HAS_SPLITARGBROW_AVX2
+#define HAS_SPLITRGBROW_AVX2
 #define HAS_SPLITUVROW_16_AVX2
 #define HAS_SPLITXRGBROW_AVX2
 #define HAS_SWAPUVROW_AVX2
@@ -388,6 +353,8 @@
 #if !defined(LIBYUV_BIT_EXACT)
 #define HAS_ABGRTOUVJROW_AVX2
 #define HAS_ABGRTOUVROW_AVX2
+#define HAS_ARGBTOUVJROW_AVX2
+#define HAS_ARGBTOUVROW_AVX2
 #endif
 
 #if defined(__x86_64__) || !defined(__pic__)
@@ -400,10 +367,13 @@
 
 // The following are available for AVX512 clang x86 platforms:
 // TODO(fbarchard): Port to GCC and Visual C
-// TODO(fbarchard): re-enable HAS_ARGBTORGB24ROW_AVX512VBMI. Issue libyuv:789
-#if !defined(LIBYUV_DISABLE_X86) && \
-    (defined(__x86_64__) || defined(__i386__)) && defined(CLANG_HAS_AVX512)
+// TODO(b/42280744): re-enable HAS_ARGBTORGB24ROW_AVX512VBMI.
+#if !defined(LIBYUV_DISABLE_X86) &&                                            \
+    (defined(__x86_64__) || defined(__i386__)) && defined(CLANG_HAS_AVX512) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
+#define HAS_COPYROW_AVX512BW
 #define HAS_ARGBTORGB24ROW_AVX512VBMI
+#define HAS_CONVERT16TO8ROW_AVX512BW
 #define HAS_MERGEUVROW_AVX512BW
 #endif
 
@@ -440,6 +410,7 @@
 #define HAS_ARGBTORGB565DITHERROW_NEON
 #define HAS_ARGBTORGB565ROW_NEON
 #define HAS_ARGBTOUV444ROW_NEON
+#define HAS_ARGBTOUVJ444ROW_NEON
 #define HAS_ARGBTOUVJROW_NEON
 #define HAS_ARGBTOUVROW_NEON
 #define HAS_ARGBTOYJROW_NEON
@@ -451,6 +422,7 @@
 #define HAS_BGRATOYROW_NEON
 #define HAS_BYTETOFLOATROW_NEON
 #define HAS_CONVERT16TO8ROW_NEON
+#define HAS_CONVERT8TO8ROW_NEON
 #define HAS_COPYROW_NEON
 #define HAS_DETILEROW_16_NEON
 #define HAS_DETILEROW_NEON
@@ -553,6 +525,133 @@
 
 // The following are available on AArch64 platforms:
 #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
+#define HAS_ARGBTOAR30ROW_NEON
+#define HAS_ABGRTOAR30ROW_NEON
+#define HAS_I210ALPHATOARGBROW_NEON
+#define HAS_I410ALPHATOARGBROW_NEON
+#define HAS_I210TOARGBROW_NEON
+#define HAS_I410TOARGBROW_NEON
+#define HAS_I210TOAR30ROW_NEON
+#define HAS_I410TOAR30ROW_NEON
+#define HAS_I212TOARGBROW_NEON
+#define HAS_I212TOAR30ROW_NEON
+#define HAS_I422TOAR30ROW_NEON
+#define HAS_P210TOAR30ROW_NEON
+#define HAS_P210TOARGBROW_NEON
+#define HAS_P410TOAR30ROW_NEON
+#define HAS_P410TOARGBROW_NEON
+
+#define HAS_ABGRTOYJROW_NEON_DOTPROD
+#define HAS_ABGRTOYROW_NEON_DOTPROD
+#define HAS_ARGBTOYJROW_NEON_DOTPROD
+#define HAS_ARGBTOYROW_NEON_DOTPROD
+#define HAS_BGRATOYROW_NEON_DOTPROD
+#define HAS_RGBATOYJROW_NEON_DOTPROD
+#define HAS_RGBATOYROW_NEON_DOTPROD
+#define HAS_ARGBGRAYROW_NEON_DOTPROD
+#define HAS_ARGBSEPIAROW_NEON_DOTPROD
+
+#define HAS_ARGBCOLORMATRIXROW_NEON_I8MM
+#define HAS_ARGBTOUV444ROW_NEON_I8MM
+#define HAS_ARGBTOUVJ444ROW_NEON_I8MM
+#endif
+
+// The following are available on AArch64 SVE platforms:
+#if !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__)
+#define HAS_ABGRTOUVJROW_SVE2
+#define HAS_ABGRTOUVROW_SVE2
+#define HAS_ARGB1555TOARGBROW_SVE2
+#define HAS_ARGBTORAWROW_SVE2
+#define HAS_ARGBTORGB24ROW_SVE2
+#define HAS_ARGBTORGB565DITHERROW_SVE2
+#define HAS_ARGBTORGB565ROW_SVE2
+#define HAS_ARGBTOUVJROW_SVE2
+#define HAS_ARGBTOUVROW_SVE2
+#define HAS_AYUVTOUVROW_SVE2
+#define HAS_AYUVTOVUROW_SVE2
+#define HAS_BGRATOUVROW_SVE2
+#define HAS_CONVERT8TO8ROW_SVE2
+#define HAS_DIVIDEROW_16_SVE2
+#define HAS_HALFFLOATROW_SVE2
+#define HAS_I210ALPHATOARGBROW_SVE2
+#define HAS_I210TOAR30ROW_SVE2
+#define HAS_I210TOARGBROW_SVE2
+#define HAS_I212TOAR30ROW_SVE2
+#define HAS_I212TOARGBROW_SVE2
+#define HAS_I400TOARGBROW_SVE2
+#define HAS_I410ALPHATOARGBROW_SVE2
+#define HAS_I410TOAR30ROW_SVE2
+#define HAS_I410TOARGBROW_SVE2
+#define HAS_I422ALPHATOARGBROW_SVE2
+#define HAS_I422TOARGB1555ROW_SVE2
+#define HAS_I422TOARGB4444ROW_SVE2
+#define HAS_I422TOARGBROW_SVE2
+#define HAS_I422TORGB24ROW_SVE2
+#define HAS_I422TORGB565ROW_SVE2
+#define HAS_I422TORGBAROW_SVE2
+#define HAS_I444ALPHATOARGBROW_SVE2
+#define HAS_I444TOARGBROW_SVE2
+#define HAS_NV12TOARGBROW_SVE2
+#define HAS_NV12TORGB24ROW_SVE2
+#define HAS_NV21TOARGBROW_SVE2
+#define HAS_NV21TORGB24ROW_SVE2
+#define HAS_P210TOAR30ROW_SVE2
+#define HAS_P210TOARGBROW_SVE2
+#define HAS_P410TOAR30ROW_SVE2
+#define HAS_P410TOARGBROW_SVE2
+#define HAS_RAWTOARGBROW_SVE2
+#define HAS_RAWTORGB24ROW_SVE2
+#define HAS_RAWTORGBAROW_SVE2
+#define HAS_RGB24TOARGBROW_SVE2
+#define HAS_RGBATOUVROW_SVE2
+#define HAS_UYVYTOARGBROW_SVE2
+#define HAS_YUY2TOARGBROW_SVE2
+#endif
+
+// The following are available on AArch64 SME platforms:
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+#define HAS_ARGBMULTIPLYROW_SME
+#define HAS_CONVERT16TO8ROW_SME
+#define HAS_CONVERT8TO8ROW_SME
+#define HAS_COPYROW_SME
+#define HAS_I210ALPHATOARGBROW_SME
+#define HAS_I210TOAR30ROW_SME
+#define HAS_I210TOARGBROW_SME
+#define HAS_I212TOAR30ROW_SME
+#define HAS_I212TOARGBROW_SME
+#define HAS_I400TOARGBROW_SME
+#define HAS_I410ALPHATOARGBROW_SME
+#define HAS_I410TOAR30ROW_SME
+#define HAS_I410TOARGBROW_SME
+#define HAS_I422ALPHATOARGBROW_SME
+#define HAS_I422TOARGB1555ROW_SME
+#define HAS_I422TOARGB4444ROW_SME
+#define HAS_I422TOARGBROW_SME
+#define HAS_I422TORGB24ROW_SME
+#define HAS_I422TORGB565ROW_SME
+#define HAS_I422TORGBAROW_SME
+#define HAS_I444ALPHATOARGBROW_SME
+#define HAS_I444TOARGBROW_SME
+#define HAS_INTERPOLATEROW_16_SME
+#define HAS_INTERPOLATEROW_16TO8_SME
+#define HAS_INTERPOLATEROW_SME
+#define HAS_MERGEUVROW_16_SME
+#define HAS_MERGEUVROW_SME
+#define HAS_MULTIPLYROW_16_SME
+#define HAS_NV12TOARGBROW_SME
+#define HAS_NV12TORGB24ROW_SME
+#define HAS_NV21TOARGBROW_SME
+#define HAS_NV21TORGB24ROW_SME
+#define HAS_P210TOAR30ROW_SME
+#define HAS_P210TOARGBROW_SME
+#define HAS_P410TOAR30ROW_SME
+#define HAS_P410TOARGBROW_SME
+#define HAS_YUY2TOARGBROW_SME
+#endif
+
+// The following are available on AArch64 platforms:
+#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
 #define HAS_GAUSSCOL_F32_NEON
 #define HAS_GAUSSROW_F32_NEON
 #define HAS_INTERPOLATEROW_16TO8_NEON
@@ -573,7 +672,8 @@
 #define HAS_ARGBEXTRACTALPHAROW_MSA
 #define HAS_ARGBGRAYROW_MSA
 #define HAS_ARGBMIRRORROW_MSA
-#define HAS_ARGBMULTIPLYROW_MSA
+// TODO: Re-enable once rounding behaviour is fixed.
+// #define HAS_ARGBMULTIPLYROW_MSA
 #define HAS_ARGBQUANTIZEROW_MSA
 #define HAS_ARGBSEPIAROW_MSA
 #define HAS_ARGBSETROW_MSA
@@ -672,7 +772,8 @@
 #define HAS_ARGBTOUVROW_LSX
 #define HAS_ARGBTOYJROW_LSX
 #define HAS_ARGBMIRRORROW_LSX
-#define HAS_ARGBMULTIPLYROW_LSX
+// TODO: Re-enable once rounding behaviour is fixed.
+// #define HAS_ARGBMULTIPLYROW_LSX
 #define HAS_BGRATOUVROW_LSX
 #define HAS_BGRATOYROW_LSX
 #define HAS_I400TOARGBROW_LSX
@@ -739,7 +840,8 @@
 #define HAS_ARGBATTENUATEROW_LASX
 #define HAS_ARGBGRAYROW_LASX
 #define HAS_ARGBMIRRORROW_LASX
-#define HAS_ARGBMULTIPLYROW_LASX
+// TODO: Re-enable once rounding behaviour is fixed.
+// #define HAS_ARGBMULTIPLYROW_LASX
 #define HAS_ARGBSEPIAROW_LASX
 #define HAS_ARGBSHADEROW_LASX
 #define HAS_ARGBSHUFFLEROW_LASX
@@ -793,29 +895,73 @@
 #define HAS_RAWTOYJROW_LASX
 #endif
 
+#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 12000 && \
+    !defined(LIBYUV_DISABLE_RVV)
+#define LIBYUV_DISABLE_RVV 1
+#endif
+
 #if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector)
-#define HAS_COPYROW_RVV
-#if __riscv_v_intrinsic == 11000
-#define HAS_AB64TOARGBROW_RVV
+#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic > 11000
+// Since v0.12, TUPLE_TYPE is introduced for segment load and store.
+#define LIBYUV_RVV_HAS_TUPLE_TYPE
+// Since v0.12, VXRM(fixed-point rounding mode) is included in arguments of
+// fixed-point intrinsics.
+#define LIBYUV_RVV_HAS_VXRM_ARG
+#endif
+#endif
+
+// The following are available for RVV 1.2
+#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector)
 #define HAS_ABGRTOYJROW_RVV
 #define HAS_ABGRTOYROW_RVV
 #define HAS_AR64TOARGBROW_RVV
-#define HAS_AR64TOAB64ROW_RVV
-#define HAS_ARGBATTENUATEROW_RVV
-#define HAS_ARGBBLENDROW_RVV
 #define HAS_ARGBCOPYYTOALPHAROW_RVV
 #define HAS_ARGBEXTRACTALPHAROW_RVV
-#define HAS_ARGBTOAB64ROW_RVV
-#define HAS_ARGBTOABGRROW_RVV
 #define HAS_ARGBTOAR64ROW_RVV
-#define HAS_ARGBTOBGRAROW_RVV
-#define HAS_ARGBTORAWROW_RVV
-#define HAS_ARGBTORGB24ROW_RVV
-#define HAS_ARGBTORGBAROW_RVV
 #define HAS_ARGBTOYJROW_RVV
 #define HAS_ARGBTOYMATRIXROW_RVV
 #define HAS_ARGBTOYROW_RVV
 #define HAS_BGRATOYROW_RVV
+#define HAS_COPYROW_RVV
+#define HAS_INTERPOLATEROW_RVV
+#define HAS_RAWTOYJROW_RVV
+#define HAS_RAWTOYROW_RVV
+#define HAS_RGB24TOYJROW_RVV
+#define HAS_RGB24TOYROW_RVV
+#define HAS_RGBATOYJROW_RVV
+#define HAS_RGBATOYMATRIXROW_RVV
+#define HAS_RGBATOYROW_RVV
+#define HAS_RGBTOYMATRIXROW_RVV
+#define HAS_SPLITARGBROW_RVV
+#define HAS_SPLITRGBROW_RVV
+#define HAS_SPLITUVROW_RVV
+#define HAS_SPLITXRGBROW_RVV
+#endif
+
+// The following are available for RVV 1.1
+// TODO(fbarchard): Port to RVV 1.2 (tuple)
+// missing support for vcreate_v:
+//  __riscv_vcreate_v_u16m2x2
+//  __riscv_vcreate_v_u16m2x4
+//  __riscv_vcreate_v_u16m4x2
+//  __riscv_vcreate_v_u8m1x3
+//  __riscv_vcreate_v_u8m1x4
+//  __riscv_vcreate_v_u8m2x2
+//  __riscv_vcreate_v_u8m2x3
+//  __riscv_vcreate_v_u8m2x4
+//  __riscv_vcreate_v_u8m4x2
+#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) && \
+    !defined(LIBYUV_RVV_HAS_TUPLE_TYPE)
+#define HAS_AB64TOARGBROW_RVV
+#define HAS_AR64TOAB64ROW_RVV
+#define HAS_ARGBATTENUATEROW_RVV
+#define HAS_ARGBBLENDROW_RVV
+#define HAS_ARGBTOAB64ROW_RVV
+#define HAS_ARGBTOABGRROW_RVV
+#define HAS_ARGBTOBGRAROW_RVV
+#define HAS_ARGBTORAWROW_RVV
+#define HAS_ARGBTORGB24ROW_RVV
+#define HAS_ARGBTORGBAROW_RVV
 #define HAS_BLENDPLANEROW_RVV
 #define HAS_I400TOARGBROW_RVV
 #define HAS_I422ALPHATOARGBROW_RVV
@@ -825,7 +971,6 @@
 #define HAS_I444ALPHATOARGBROW_RVV
 #define HAS_I444TOARGBROW_RVV
 #define HAS_I444TORGB24ROW_RVV
-#define HAS_INTERPOLATEROW_RVV
 #define HAS_J400TOARGBROW_RVV
 #define HAS_MERGEARGBROW_RVV
 #define HAS_MERGERGBROW_RVV
@@ -838,21 +983,8 @@
 #define HAS_RAWTOARGBROW_RVV
 #define HAS_RAWTORGB24ROW_RVV
 #define HAS_RAWTORGBAROW_RVV
-#define HAS_RAWTOYJROW_RVV
-#define HAS_RAWTOYROW_RVV
 #define HAS_RGB24TOARGBROW_RVV
-#define HAS_RGB24TOYJROW_RVV
-#define HAS_RGB24TOYROW_RVV
 #define HAS_RGBATOARGBROW_RVV
-#define HAS_RGBATOYJROW_RVV
-#define HAS_RGBATOYMATRIXROW_RVV
-#define HAS_RGBATOYROW_RVV
-#define HAS_RGBTOYMATRIXROW_RVV
-#define HAS_SPLITARGBROW_RVV
-#define HAS_SPLITRGBROW_RVV
-#define HAS_SPLITUVROW_RVV
-#define HAS_SPLITXRGBROW_RVV
-#endif
 #endif
 
 #if defined(_MSC_VER) && !defined(__CLR_VER) && !defined(__clang__)
@@ -1013,24 +1145,204 @@
     IACA_UD_BYTES      \
   }
 
+void I210AlphaToARGBRow_NEON(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* rgb_buf,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I210AlphaToARGBRow_SVE2(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* rgb_buf,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I210AlphaToARGBRow_SME(const uint16_t* src_y,
+                            const uint16_t* src_u,
+                            const uint16_t* src_v,
+                            const uint16_t* src_a,
+                            uint8_t* rgb_buf,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I410AlphaToARGBRow_NEON(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* rgb_buf,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I410AlphaToARGBRow_SVE2(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* rgb_buf,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I410AlphaToARGBRow_SME(const uint16_t* src_y,
+                            const uint16_t* src_u,
+                            const uint16_t* src_v,
+                            const uint16_t* src_a,
+                            uint8_t* rgb_buf,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
 void I444ToARGBRow_NEON(const uint8_t* src_y,
                         const uint8_t* src_u,
                         const uint8_t* src_v,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void I444ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I444ToARGBRow_SME(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void I444ToRGB24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_u,
                          const uint8_t* src_v,
                          uint8_t* dst_rgb24,
                          const struct YuvConstants* yuvconstants,
                          int width);
+void I210ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I210ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I210ToARGBRow_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I410ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I410ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I410ToARGBRow_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I210ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I210ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I210ToAR30Row_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I410ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I410ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I410ToAR30Row_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I212ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I212ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I212ToARGBRow_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I212ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I212ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* rgb_buf,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I212ToAR30Row_SME(const uint16_t* src_y,
+                       const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint8_t* rgb_buf,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void I422ToARGBRow_NEON(const uint8_t* src_y,
                         const uint8_t* src_u,
                         const uint8_t* src_v,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void I422ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I422ToARGBRow_SME(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
+void I422ToAR30Row_NEON(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
 void I444AlphaToARGBRow_NEON(const uint8_t* src_y,
                              const uint8_t* src_u,
                              const uint8_t* src_v,
@@ -1038,6 +1350,20 @@
                              uint8_t* dst_argb,
                              const struct YuvConstants* yuvconstants,
                              int width);
+void I444AlphaToARGBRow_SVE2(const uint8_t* src_y,
+                             const uint8_t* src_u,
+                             const uint8_t* src_v,
+                             const uint8_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I444AlphaToARGBRow_SME(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            const uint8_t* src_a,
+                            uint8_t* dst_argb,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
 void I422AlphaToARGBRow_NEON(const uint8_t* src_y,
                              const uint8_t* src_u,
                              const uint8_t* src_v,
@@ -1045,41 +1371,125 @@
                              uint8_t* dst_argb,
                              const struct YuvConstants* yuvconstants,
                              int width);
+void I422AlphaToARGBRow_SVE2(const uint8_t* src_y,
+                             const uint8_t* src_u,
+                             const uint8_t* src_v,
+                             const uint8_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width);
+void I422AlphaToARGBRow_SME(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            const uint8_t* src_a,
+                            uint8_t* dst_argb,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
 void I422ToRGBARow_NEON(const uint8_t* src_y,
                         const uint8_t* src_u,
                         const uint8_t* src_v,
                         uint8_t* dst_rgba,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void I422ToRGBARow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_rgba,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I422ToRGBARow_SME(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_rgba,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void I422ToRGB24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_u,
                          const uint8_t* src_v,
                          uint8_t* dst_rgb24,
                          const struct YuvConstants* yuvconstants,
                          int width);
+void I422ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_u,
+                         const uint8_t* src_v,
+                         uint8_t* dst_rgb24,
+                         const struct YuvConstants* yuvconstants,
+                         int width);
+void I422ToRGB24Row_SME(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
 void I422ToRGB565Row_NEON(const uint8_t* src_y,
                           const uint8_t* src_u,
                           const uint8_t* src_v,
                           uint8_t* dst_rgb565,
                           const struct YuvConstants* yuvconstants,
                           int width);
+void I422ToRGB565Row_SVE2(const uint8_t* src_y,
+                          const uint8_t* src_u,
+                          const uint8_t* src_v,
+                          uint8_t* dst_rgb565,
+                          const struct YuvConstants* yuvconstants,
+                          int width);
+void I422ToRGB565Row_SME(const uint8_t* src_y,
+                         const uint8_t* src_u,
+                         const uint8_t* src_v,
+                         uint8_t* dst_rgb565,
+                         const struct YuvConstants* yuvconstants,
+                         int width);
 void I422ToARGB1555Row_NEON(const uint8_t* src_y,
                             const uint8_t* src_u,
                             const uint8_t* src_v,
                             uint8_t* dst_argb1555,
                             const struct YuvConstants* yuvconstants,
                             int width);
+void I422ToARGB1555Row_SVE2(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            uint8_t* dst_argb1555,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I422ToARGB1555Row_SME(const uint8_t* src_y,
+                           const uint8_t* src_u,
+                           const uint8_t* src_v,
+                           uint8_t* dst_argb1555,
+                           const struct YuvConstants* yuvconstants,
+                           int width);
 void I422ToARGB4444Row_NEON(const uint8_t* src_y,
                             const uint8_t* src_u,
                             const uint8_t* src_v,
                             uint8_t* dst_argb4444,
                             const struct YuvConstants* yuvconstants,
                             int width);
+void I422ToARGB4444Row_SVE2(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            uint8_t* dst_argb4444,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I422ToARGB4444Row_SME(const uint8_t* src_y,
+                           const uint8_t* src_u,
+                           const uint8_t* src_v,
+                           uint8_t* dst_argb4444,
+                           const struct YuvConstants* yuvconstants,
+                           int width);
 void NV12ToARGBRow_NEON(const uint8_t* src_y,
                         const uint8_t* src_uv,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void NV12ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void NV12ToARGBRow_SME(const uint8_t* src_y,
+                       const uint8_t* src_uv,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void NV12ToRGB565Row_NEON(const uint8_t* src_y,
                           const uint8_t* src_uv,
                           uint8_t* dst_rgb565,
@@ -1090,16 +1500,46 @@
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void NV21ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_vu,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void NV21ToARGBRow_SME(const uint8_t* src_y,
+                       const uint8_t* src_vu,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void NV12ToRGB24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_uv,
                          uint8_t* dst_rgb24,
                          const struct YuvConstants* yuvconstants,
                          int width);
+void NV12ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_uv,
+                         uint8_t* dst_rgb24,
+                         const struct YuvConstants* yuvconstants,
+                         int width);
+void NV12ToRGB24Row_SME(const uint8_t* src_y,
+                        const uint8_t* src_uv,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
 void NV21ToRGB24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_vu,
                          uint8_t* dst_rgb24,
                          const struct YuvConstants* yuvconstants,
                          int width);
+void NV21ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_vu,
+                         uint8_t* dst_rgb24,
+                         const struct YuvConstants* yuvconstants,
+                         int width);
+void NV21ToRGB24Row_SME(const uint8_t* src_y,
+                        const uint8_t* src_vu,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
 void NV21ToYUV24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_vu,
                          uint8_t* dst_yuv24,
@@ -1108,10 +1548,26 @@
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void YUY2ToARGBRow_SVE2(const uint8_t* src_yuy2,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void YUY2ToARGBRow_SME(const uint8_t* src_yuy2,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void UYVYToARGBRow_NEON(const uint8_t* src_uyvy,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void UYVYToARGBRow_SVE2(const uint8_t* src_uyvy,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void UYVYToARGBRow_SME(const uint8_t* src_uyvy,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void I444ToARGBRow_RVV(const uint8_t* src_y,
                        const uint8_t* src_u,
                        const uint8_t* src_v,
@@ -1409,6 +1865,18 @@
 void ARGBToYJRow_NEON(const uint8_t* src_argb, uint8_t* dst_yj, int width);
 void ABGRToYJRow_NEON(const uint8_t* src_abgr, uint8_t* dst_yj, int width);
 void RGBAToYJRow_NEON(const uint8_t* src_rgba, uint8_t* dst_yj, int width);
+void ARGBToYRow_NEON_DotProd(const uint8_t* src_argb,
+                             uint8_t* dst_y,
+                             int width);
+void ARGBToYJRow_NEON_DotProd(const uint8_t* src_argb,
+                              uint8_t* dst_yj,
+                              int width);
+void ABGRToYJRow_NEON_DotProd(const uint8_t* src_abgr,
+                              uint8_t* dst_yj,
+                              int width);
+void RGBAToYJRow_NEON_DotProd(const uint8_t* src_rgba,
+                              uint8_t* dst_yj,
+                              int width);
 void ARGBToYRow_RVV(const uint8_t* src_argb, uint8_t* dst_y, int width);
 void ARGBToYJRow_RVV(const uint8_t* src_argb, uint8_t* dst_yj, int width);
 void ABGRToYJRow_RVV(const uint8_t* src_rgba, uint8_t* dst_yj, int width);
@@ -1427,11 +1895,28 @@
                          uint8_t* dst_u,
                          uint8_t* dst_v,
                          int width);
+void ARGBToUV444Row_NEON_I8MM(const uint8_t* src_argb,
+                              uint8_t* dst_u,
+                              uint8_t* dst_v,
+                              int width);
+void ARGBToUVJ444Row_NEON(const uint8_t* src_argb,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
+void ARGBToUVJ444Row_NEON_I8MM(const uint8_t* src_argb,
+                               uint8_t* dst_u,
+                               uint8_t* dst_v,
+                               int width);
 void ARGBToUVRow_NEON(const uint8_t* src_argb,
                       int src_stride_argb,
                       uint8_t* dst_u,
                       uint8_t* dst_v,
                       int width);
+void ARGBToUVRow_SVE2(const uint8_t* src_argb,
+                      int src_stride_argb,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width);
 void ARGBToUV444Row_MSA(const uint8_t* src_argb,
                         uint8_t* dst_u,
                         uint8_t* dst_v,
@@ -1464,26 +1949,51 @@
                        uint8_t* dst_u,
                        uint8_t* dst_v,
                        int width);
+void ARGBToUVJRow_SVE2(const uint8_t* src_argb,
+                       int src_stride_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width);
 void ABGRToUVJRow_NEON(const uint8_t* src_abgr,
                        int src_stride_abgr,
                        uint8_t* dst_uj,
                        uint8_t* dst_vj,
                        int width);
+void ABGRToUVJRow_SVE2(const uint8_t* src_abgr,
+                       int src_stride_abgr,
+                       uint8_t* dst_uj,
+                       uint8_t* dst_vj,
+                       int width);
 void BGRAToUVRow_NEON(const uint8_t* src_bgra,
                       int src_stride_bgra,
                       uint8_t* dst_u,
                       uint8_t* dst_v,
                       int width);
+void BGRAToUVRow_SVE2(const uint8_t* src_bgra,
+                      int src_stride_bgra,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width);
 void ABGRToUVRow_NEON(const uint8_t* src_abgr,
                       int src_stride_abgr,
                       uint8_t* dst_u,
                       uint8_t* dst_v,
                       int width);
+void ABGRToUVRow_SVE2(const uint8_t* src_abgr,
+                      int src_stride_abgr,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width);
 void RGBAToUVRow_NEON(const uint8_t* src_rgba,
                       int src_stride_rgba,
                       uint8_t* dst_u,
                       uint8_t* dst_v,
                       int width);
+void RGBAToUVRow_SVE2(const uint8_t* src_rgba,
+                      int src_stride_rgba,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width);
 void RGB24ToUVRow_NEON(const uint8_t* src_rgb24,
                        int src_stride_rgb24,
                        uint8_t* dst_u,
@@ -1632,6 +2142,15 @@
 void BGRAToYRow_NEON(const uint8_t* src_bgra, uint8_t* dst_y, int width);
 void ABGRToYRow_NEON(const uint8_t* src_abgr, uint8_t* dst_y, int width);
 void RGBAToYRow_NEON(const uint8_t* src_rgba, uint8_t* dst_y, int width);
+void BGRAToYRow_NEON_DotProd(const uint8_t* src_bgra,
+                             uint8_t* dst_y,
+                             int width);
+void ABGRToYRow_NEON_DotProd(const uint8_t* src_abgr,
+                             uint8_t* dst_y,
+                             int width);
+void RGBAToYRow_NEON_DotProd(const uint8_t* src_rgba,
+                             uint8_t* dst_y,
+                             int width);
 void RGB24ToYRow_NEON(const uint8_t* src_rgb24, uint8_t* dst_y, int width);
 void RGB24ToYJRow_NEON(const uint8_t* src_rgb24, uint8_t* dst_yj, int width);
 void RAWToYRow_NEON(const uint8_t* src_raw, uint8_t* dst_y, int width);
@@ -1709,12 +2228,33 @@
 void RGB24ToYJRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void RAWToYJRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void ARGBToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void ARGBToYRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                 uint8_t* dst_ptr,
+                                 int width);
 void ARGBToYJRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void ARGBToYJRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                  uint8_t* dst_ptr,
+                                  int width);
 void ABGRToYJRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void ABGRToYJRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                  uint8_t* dst_ptr,
+                                  int width);
 void RGBAToYJRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void RGBAToYJRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                  uint8_t* dst_ptr,
+                                  int width);
 void BGRAToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void BGRAToYRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                 uint8_t* dst_ptr,
+                                 int width);
 void ABGRToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void ABGRToYRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                 uint8_t* dst_ptr,
+                                 int width);
 void RGBAToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void RGBAToYRow_Any_NEON_DotProd(const uint8_t* src_ptr,
+                                 uint8_t* dst_ptr,
+                                 int width);
 void RGB24ToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void RGB24ToYJRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void RAWToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
@@ -1874,11 +2414,28 @@
                              uint8_t* dst_u,
                              uint8_t* dst_v,
                              int width);
+void ARGBToUV444Row_Any_NEON_I8MM(const uint8_t* src_ptr,
+                                  uint8_t* dst_u,
+                                  uint8_t* dst_v,
+                                  int width);
+void ARGBToUVJ444Row_Any_NEON(const uint8_t* src_ptr,
+                              uint8_t* dst_u,
+                              uint8_t* dst_v,
+                              int width);
+void ARGBToUVJ444Row_Any_NEON_I8MM(const uint8_t* src_ptr,
+                                   uint8_t* dst_u,
+                                   uint8_t* dst_v,
+                                   int width);
 void ARGBToUVRow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width);
+void ARGBToUVRow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
 void ARGBToUV444Row_Any_MSA(const uint8_t* src_ptr,
                             uint8_t* dst_u,
                             uint8_t* dst_v,
@@ -1911,26 +2468,51 @@
                            uint8_t* dst_u,
                            uint8_t* dst_v,
                            int width);
+void ARGBToUVJRow_Any_SVE2(const uint8_t* src_ptr,
+                           int src_stride,
+                           uint8_t* dst_u,
+                           uint8_t* dst_v,
+                           int width);
 void ABGRToUVJRow_Any_NEON(const uint8_t* src_ptr,
                            int src_stride,
                            uint8_t* dst_u,
                            uint8_t* dst_v,
                            int width);
+void ABGRToUVJRow_Any_SVE2(const uint8_t* src_ptr,
+                           int src_stride,
+                           uint8_t* dst_u,
+                           uint8_t* dst_v,
+                           int width);
 void BGRAToUVRow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width);
+void BGRAToUVRow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
 void ABGRToUVRow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width);
+void ABGRToUVRow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
 void RGBAToUVRow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width);
+void RGBAToUVRow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
 void RGB24ToUVRow_Any_NEON(const uint8_t* src_ptr,
                            int src_stride,
                            uint8_t* dst_u,
@@ -2156,11 +2738,43 @@
                               uint8_t* dst_v,
                               int width);
 
+void ARGBToUVJ444Row_SSSE3(const uint8_t* src_argb,
+                           uint8_t* dst_u,
+                           uint8_t* dst_v,
+                           int width);
+void ARGBToUVJ444Row_Any_SSSE3(const uint8_t* src_ptr,
+                               uint8_t* dst_u,
+                               uint8_t* dst_v,
+                               int width);
+
+void ARGBToUV444Row_AVX2(const uint8_t* src_argb,
+                         uint8_t* dst_u,
+                         uint8_t* dst_v,
+                         int width);
+void ARGBToUV444Row_Any_AVX2(const uint8_t* src_ptr,
+                             uint8_t* dst_u,
+                             uint8_t* dst_v,
+                             int width);
+
+void ARGBToUVJ444Row_AVX2(const uint8_t* src_argb,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width);
+void ARGBToUVJ444Row_Any_AVX2(const uint8_t* src_ptr,
+                              uint8_t* dst_u,
+                              uint8_t* dst_v,
+                              int width);
+
 void ARGBToUV444Row_C(const uint8_t* src_argb,
                       uint8_t* dst_u,
                       uint8_t* dst_v,
                       int width);
 
+void ARGBToUVJ444Row_C(const uint8_t* src_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width);
+
 void MirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width);
 void MirrorRow_SSSE3(const uint8_t* src, uint8_t* dst, int width);
 void MirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width);
@@ -2429,6 +3043,10 @@
                      const uint8_t* src_v,
                      uint8_t* dst_uv,
                      int width);
+void MergeUVRow_SME(const uint8_t* src_u,
+                    const uint8_t* src_v,
+                    uint8_t* dst_uv,
+                    int width);
 void MergeUVRow_MSA(const uint8_t* src_u,
                     const uint8_t* src_v,
                     uint8_t* dst_uv,
@@ -2504,6 +3122,16 @@
                        uint8_t* dst_g,
                        uint8_t* dst_b,
                        int width);
+void SplitRGBRow_SSE41(const uint8_t* src_rgb,
+                       uint8_t* dst_r,
+                       uint8_t* dst_g,
+                       uint8_t* dst_b,
+                       int width);
+void SplitRGBRow_AVX2(const uint8_t* src_rgb,
+                      uint8_t* dst_r,
+                      uint8_t* dst_g,
+                      uint8_t* dst_b,
+                      int width);
 void SplitRGBRow_NEON(const uint8_t* src_rgb,
                       uint8_t* dst_r,
                       uint8_t* dst_g,
@@ -2519,6 +3147,16 @@
                            uint8_t* dst_g,
                            uint8_t* dst_b,
                            int width);
+void SplitRGBRow_Any_SSE41(const uint8_t* src_ptr,
+                           uint8_t* dst_r,
+                           uint8_t* dst_g,
+                           uint8_t* dst_b,
+                           int width);
+void SplitRGBRow_Any_AVX2(const uint8_t* src_ptr,
+                          uint8_t* dst_r,
+                          uint8_t* dst_g,
+                          uint8_t* dst_b,
+                          int width);
 void SplitRGBRow_Any_NEON(const uint8_t* src_ptr,
                           uint8_t* dst_r,
                           uint8_t* dst_g,
@@ -2952,6 +3590,11 @@
                             uint16_t* dst_uv,
                             int depth,
                             int width);
+void MergeUVRow_16_SME(const uint16_t* src_u,
+                       const uint16_t* src_v,
+                       uint16_t* dst_uv,
+                       int depth,
+                       int width);
 
 void SplitUVRow_16_C(const uint16_t* src_uv,
                      uint16_t* dst_u,
@@ -2999,6 +3642,10 @@
                              uint16_t* dst_ptr,
                              int scale,
                              int width);
+void MultiplyRow_16_SME(const uint16_t* src_y,
+                        uint16_t* dst_y,
+                        int scale,
+                        int width);
 
 void DivideRow_16_C(const uint16_t* src_y,
                     uint16_t* dst_y,
@@ -3016,6 +3663,10 @@
                        uint16_t* dst_y,
                        int scale,
                        int width);
+void DivideRow_16_SVE2(const uint16_t* src_y,
+                       uint16_t* dst_y,
+                       int scale,
+                       int width);
 void DivideRow_16_Any_NEON(const uint16_t* src_ptr,
                            uint16_t* dst_ptr,
                            int scale,
@@ -3054,6 +3705,10 @@
                           uint8_t* dst_y,
                           int scale,
                           int width);
+void Convert16To8Row_AVX512BW(const uint16_t* src_y,
+                              uint8_t* dst_y,
+                              int scale,
+                              int width);
 void Convert16To8Row_Any_SSSE3(const uint16_t* src_ptr,
                                uint8_t* dst_ptr,
                                int scale,
@@ -3062,6 +3717,10 @@
                               uint8_t* dst_ptr,
                               int scale,
                               int width);
+void Convert16To8Row_Any_AVX512BW(const uint16_t* src_ptr,
+                                  uint8_t* dst_ptr,
+                                  int scale,
+                                  int width);
 void Convert16To8Row_NEON(const uint16_t* src_y,
                           uint8_t* dst_y,
                           int scale,
@@ -3070,16 +3729,59 @@
                               uint8_t* dst_ptr,
                               int scale,
                               int width);
+void Convert16To8Row_SME(const uint16_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int width);
+
+void Convert8To8Row_C(const uint8_t* src_y,
+                      uint8_t* dst_y,
+                      int scale,
+                      int bias,
+                      int width);
+void Convert8To8Row_NEON(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width);
+void Convert8To8Row_Any_NEON(const uint8_t* src_ptr,
+                             uint8_t* dst_ptr,
+                             int scale,
+                             int bias,
+                             int width);
+void Convert8To8Row_SVE2(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width);
+void Convert8To8Row_SME(const uint8_t* src_y,
+                        uint8_t* dst_y,
+                        int scale,
+                        int bias,
+                        int width);
+void Convert8To8Row_AVX2(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width);
+void Convert8To8Row_Any_AVX2(const uint8_t* src_ptr,
+                             uint8_t* dst_ptr,
+                             int scale,
+                             int bias,
+                             int width);
 
 void CopyRow_SSE2(const uint8_t* src, uint8_t* dst, int width);
 void CopyRow_AVX(const uint8_t* src, uint8_t* dst, int width);
+void CopyRow_AVX512BW(const uint8_t* src, uint8_t* dst, int width);
 void CopyRow_ERMS(const uint8_t* src, uint8_t* dst, int width);
 void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width);
+void CopyRow_SME(const uint8_t* src, uint8_t* dst, int width);
 void CopyRow_MIPS(const uint8_t* src, uint8_t* dst, int count);
 void CopyRow_RVV(const uint8_t* src, uint8_t* dst, int count);
 void CopyRow_C(const uint8_t* src, uint8_t* dst, int count);
 void CopyRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void CopyRow_Any_AVX(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
+void CopyRow_Any_AVX512BW(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void CopyRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 
 void CopyRow_16_C(const uint16_t* src, uint16_t* dst, int count);
@@ -3217,6 +3919,7 @@
                           uint8_t* dst_argb,
                           int width);
 void RAWToARGBRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_argb, int width);
+void RAWToARGBRow_AVX2(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToRGBARow_SSSE3(const uint8_t* src_raw, uint8_t* dst_rgba, int width);
 void RAWToRGB24Row_SSSE3(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
 void RGB565ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width);
@@ -3235,6 +3938,9 @@
 void RGB24ToARGBRow_NEON(const uint8_t* src_rgb24,
                          uint8_t* dst_argb,
                          int width);
+void RGB24ToARGBRow_SVE2(const uint8_t* src_rgb24,
+                         uint8_t* dst_argb,
+                         int width);
 void RGB24ToARGBRow_MSA(const uint8_t* src_rgb24, uint8_t* dst_argb, int width);
 void RGB24ToARGBRow_LSX(const uint8_t* src_rgb24, uint8_t* dst_argb, int width);
 void RGB24ToARGBRow_LASX(const uint8_t* src_rgb24,
@@ -3242,13 +3948,16 @@
                          int width);
 void RGB24ToARGBRow_RVV(const uint8_t* src_rgb24, uint8_t* dst_argb, int width);
 void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width);
+void RAWToARGBRow_SVE2(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToRGBARow_NEON(const uint8_t* src_raw, uint8_t* dst_rgba, int width);
+void RAWToRGBARow_SVE2(const uint8_t* src_raw, uint8_t* dst_rgba, int width);
 void RAWToARGBRow_MSA(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToARGBRow_LSX(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToARGBRow_LASX(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToARGBRow_RVV(const uint8_t* src_raw, uint8_t* dst_argb, int width);
 void RAWToRGBARow_RVV(const uint8_t* src_raw, uint8_t* dst_rgba, int width);
 void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
+void RAWToRGB24Row_SVE2(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
 void RAWToRGB24Row_MSA(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
 void RAWToRGB24Row_LSX(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
 void RAWToRGB24Row_RVV(const uint8_t* src_raw, uint8_t* dst_rgb24, int width);
@@ -3267,6 +3976,9 @@
 void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555,
                             uint8_t* dst_argb,
                             int width);
+void ARGB1555ToARGBRow_SVE2(const uint8_t* src_argb1555,
+                            uint8_t* dst_argb,
+                            int width);
 void ARGB1555ToARGBRow_MSA(const uint8_t* src_argb1555,
                            uint8_t* dst_argb,
                            int width);
@@ -3310,6 +4022,7 @@
 void RAWToARGBRow_Any_SSSE3(const uint8_t* src_ptr,
                             uint8_t* dst_ptr,
                             int width);
+void RAWToARGBRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void RAWToRGBARow_Any_SSSE3(const uint8_t* src_ptr,
                             uint8_t* dst_ptr,
                             int width);
@@ -3435,10 +4148,17 @@
 void ARGBToRGB24Row_NEON(const uint8_t* src_argb,
                          uint8_t* dst_rgb24,
                          int width);
+void ARGBToRGB24Row_SVE2(const uint8_t* src_argb,
+                         uint8_t* dst_rgb24,
+                         int width);
 void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width);
+void ARGBToRAWRow_SVE2(const uint8_t* src_argb, uint8_t* dst_raw, int width);
 void ARGBToRGB565Row_NEON(const uint8_t* src_argb,
                           uint8_t* dst_rgb565,
                           int width);
+void ARGBToRGB565Row_SVE2(const uint8_t* src_argb,
+                          uint8_t* dst_rgb565,
+                          int width);
 void ARGBToARGB1555Row_NEON(const uint8_t* src_argb,
                             uint8_t* dst_argb1555,
                             int width);
@@ -3449,6 +4169,10 @@
                                 uint8_t* dst_rgb,
                                 uint32_t dither4,
                                 int width);
+void ARGBToRGB565DitherRow_SVE2(const uint8_t* src_argb,
+                                uint8_t* dst_rgb,
+                                uint32_t dither4,
+                                int width);
 void ARGBToRGB24Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width);
 void ARGBToRAWRow_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width);
 void ARGBToRGB565Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width);
@@ -4507,6 +5231,14 @@
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void I400ToARGBRow_SVE2(const uint8_t* src_y,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void I400ToARGBRow_SME(const uint8_t* src_y,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void I400ToARGBRow_MSA(const uint8_t* src_y,
                        uint8_t* dst_argb,
                        const struct YuvConstants* yuvconstants,
@@ -4628,6 +5360,10 @@
                               const uint8_t* uv_buf,
                               uint8_t* dst_ptr,
                               int width);
+void ARGBMultiplyRow_SME(const uint8_t* src_argb,
+                         const uint8_t* src_argb1,
+                         uint8_t* dst_argb,
+                         int width);
 void ARGBMultiplyRow_MSA(const uint8_t* src_argb0,
                          const uint8_t* src_argb1,
                          uint8_t* dst_argb,
@@ -4902,6 +5638,42 @@
                             uint8_t* dst_ptr,
                             const struct YuvConstants* yuvconstants,
                             int width);
+void I210ToARGBRow_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I410ToARGBRow_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I210ToAR30Row_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I410ToAR30Row_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I212ToARGBRow_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
+void I212ToAR30Row_Any_NEON(const uint16_t* y_buf,
+                            const uint16_t* u_buf,
+                            const uint16_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
 void I444AlphaToARGBRow_Any_NEON(const uint8_t* y_buf,
                                  const uint8_t* u_buf,
                                  const uint8_t* v_buf,
@@ -4916,6 +5688,20 @@
                                  uint8_t* dst_ptr,
                                  const struct YuvConstants* yuvconstants,
                                  int width);
+void I410AlphaToARGBRow_Any_NEON(const uint16_t* y_buf,
+                                 const uint16_t* u_buf,
+                                 const uint16_t* v_buf,
+                                 const uint16_t* a_buf,
+                                 uint8_t* dst_ptr,
+                                 const struct YuvConstants* yuvconstants,
+                                 int width);
+void I210AlphaToARGBRow_Any_NEON(const uint16_t* y_buf,
+                                 const uint16_t* u_buf,
+                                 const uint16_t* v_buf,
+                                 const uint16_t* a_buf,
+                                 uint8_t* dst_ptr,
+                                 const struct YuvConstants* yuvconstants,
+                                 int width);
 void I422ToRGBARow_Any_NEON(const uint8_t* y_buf,
                             const uint8_t* u_buf,
                             const uint8_t* v_buf,
@@ -4946,6 +5732,12 @@
                               uint8_t* dst_ptr,
                               const struct YuvConstants* yuvconstants,
                               int width);
+void I422ToAR30Row_Any_NEON(const uint8_t* y_buf,
+                            const uint8_t* u_buf,
+                            const uint8_t* v_buf,
+                            uint8_t* dst_ptr,
+                            const struct YuvConstants* yuvconstants,
+                            int width);
 void NV12ToARGBRow_Any_NEON(const uint8_t* y_buf,
                             const uint8_t* uv_buf,
                             uint8_t* dst_ptr,
@@ -4983,26 +5775,74 @@
                             uint8_t* dst_ptr,
                             const struct YuvConstants* yuvconstants,
                             int width);
+void ARGBToAR30Row_NEON(const uint8_t* src, uint8_t* dst, int width);
+void ABGRToAR30Row_NEON(const uint8_t* src, uint8_t* dst, int width);
+void ABGRToAR30Row_Any_NEON(const uint8_t* src_ptr,
+                            uint8_t* dst_ptr,
+                            int width);
+void ARGBToAR30Row_Any_NEON(const uint8_t* src_ptr,
+                            uint8_t* dst_ptr,
+                            int width);
 void P210ToARGBRow_NEON(const uint16_t* y_buf,
                         const uint16_t* uv_buf,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void P210ToARGBRow_SVE2(const uint16_t* y_buf,
+                        const uint16_t* uv_buf,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void P210ToARGBRow_SME(const uint16_t* y_buf,
+                       const uint16_t* uv_buf,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void P410ToARGBRow_NEON(const uint16_t* y_buf,
                         const uint16_t* uv_buf,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void P410ToARGBRow_SVE2(const uint16_t* y_buf,
+                        const uint16_t* uv_buf,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void P410ToARGBRow_SME(const uint16_t* y_buf,
+                       const uint16_t* uv_buf,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void P210ToAR30Row_NEON(const uint16_t* y_buf,
                         const uint16_t* uv_buf,
                         uint8_t* dst_ar30,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void P210ToAR30Row_SVE2(const uint16_t* y_buf,
+                        const uint16_t* uv_buf,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void P210ToAR30Row_SME(const uint16_t* y_buf,
+                       const uint16_t* uv_buf,
+                       uint8_t* dst_ar30,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void P410ToAR30Row_NEON(const uint16_t* y_buf,
                         const uint16_t* uv_buf,
                         uint8_t* dst_ar30,
                         const struct YuvConstants* yuvconstants,
                         int width);
+void P410ToAR30Row_SVE2(const uint16_t* y_buf,
+                        const uint16_t* uv_buf,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width);
+void P410ToAR30Row_SME(const uint16_t* y_buf,
+                       const uint16_t* uv_buf,
+                       uint8_t* dst_ar30,
+                       const struct YuvConstants* yuvconstants,
+                       int width);
 void P210ToARGBRow_Any_NEON(const uint16_t* y_buf,
                             const uint16_t* uv_buf,
                             uint8_t* dst_argb,
@@ -5547,19 +6387,35 @@
                       int src_stride_ayuv,
                       uint8_t* dst_uv,
                       int width);
+void AYUVToUVRow_SVE2(const uint8_t* src_ayuv,
+                      int src_stride_ayuv,
+                      uint8_t* dst_uv,
+                      int width);
 void AYUVToVURow_NEON(const uint8_t* src_ayuv,
                       int src_stride_ayuv,
                       uint8_t* dst_vu,
                       int width);
+void AYUVToVURow_SVE2(const uint8_t* src_ayuv,
+                      int src_stride_ayuv,
+                      uint8_t* dst_vu,
+                      int width);
 void AYUVToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width);
 void AYUVToUVRow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_vu,
                           int width);
+void AYUVToUVRow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_vu,
+                          int width);
 void AYUVToVURow_Any_NEON(const uint8_t* src_ptr,
                           int src_stride,
                           uint8_t* dst_vu,
                           int width);
+void AYUVToVURow_Any_SVE2(const uint8_t* src_ptr,
+                          int src_stride,
+                          uint8_t* dst_vu,
+                          int width);
 
 void I422ToYUY2Row_C(const uint8_t* src_y,
                      const uint8_t* src_u,
@@ -5755,6 +6611,9 @@
 void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width);
 void ARGBGrayRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_argb, int width);
 void ARGBGrayRow_NEON(const uint8_t* src_argb, uint8_t* dst_argb, int width);
+void ARGBGrayRow_NEON_DotProd(const uint8_t* src_argb,
+                              uint8_t* dst_argb,
+                              int width);
 void ARGBGrayRow_MSA(const uint8_t* src_argb, uint8_t* dst_argb, int width);
 void ARGBGrayRow_LSX(const uint8_t* src_argb, uint8_t* dst_argb, int width);
 void ARGBGrayRow_LASX(const uint8_t* src_argb, uint8_t* dst_argb, int width);
@@ -5762,6 +6621,7 @@
 void ARGBSepiaRow_C(uint8_t* dst_argb, int width);
 void ARGBSepiaRow_SSSE3(uint8_t* dst_argb, int width);
 void ARGBSepiaRow_NEON(uint8_t* dst_argb, int width);
+void ARGBSepiaRow_NEON_DotProd(uint8_t* dst_argb, int width);
 void ARGBSepiaRow_MSA(uint8_t* dst_argb, int width);
 void ARGBSepiaRow_LSX(uint8_t* dst_argb, int width);
 void ARGBSepiaRow_LASX(uint8_t* dst_argb, int width);
@@ -5778,6 +6638,10 @@
                              uint8_t* dst_argb,
                              const int8_t* matrix_argb,
                              int width);
+void ARGBColorMatrixRow_NEON_I8MM(const uint8_t* src_argb,
+                                  uint8_t* dst_argb,
+                                  const int8_t* matrix_argb,
+                                  int width);
 void ARGBColorMatrixRow_MSA(const uint8_t* src_argb,
                             uint8_t* dst_argb,
                             const int8_t* matrix_argb,
@@ -5909,6 +6773,11 @@
                          ptrdiff_t src_stride,
                          int dst_width,
                          int source_y_fraction);
+void InterpolateRow_SME(uint8_t* dst_ptr,
+                        const uint8_t* src_ptr,
+                        ptrdiff_t src_stride,
+                        int dst_width,
+                        int source_y_fraction);
 void InterpolateRow_MSA(uint8_t* dst_ptr,
                         const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
@@ -5965,6 +6834,11 @@
                                 ptrdiff_t src_stride,
                                 int width,
                                 int source_y_fraction);
+void InterpolateRow_16_SME(uint16_t* dst_ptr,
+                           const uint16_t* src_ptr,
+                           ptrdiff_t src_stride,
+                           int width,
+                           int source_y_fraction);
 
 void InterpolateRow_16To8_C(uint8_t* dst_ptr,
                             const uint16_t* src_ptr,
@@ -5984,6 +6858,12 @@
                                    int scale,
                                    int width,
                                    int source_y_fraction);
+void InterpolateRow_16To8_SME(uint8_t* dst_ptr,
+                              const uint16_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              int scale,
+                              int width,
+                              int source_y_fraction);
 void InterpolateRow_16To8_AVX2(uint8_t* dst_ptr,
                                const uint16_t* src_ptr,
                                ptrdiff_t src_stride,
@@ -6198,14 +7078,14 @@
                            uint16_t* dst_ptr,
                            float param,
                            int width);
-void HalfFloat1Row_NEON(const uint16_t* src,
+void HalfFloatRow_SVE2(const uint16_t* src,
+                       uint16_t* dst,
+                       float scale,
+                       int width);
+void HalfFloat1Row_SVE2(const uint16_t* src,
                         uint16_t* dst,
                         float scale,
                         int width);
-void HalfFloat1Row_Any_NEON(const uint16_t* src_ptr,
-                            uint16_t* dst_ptr,
-                            float param,
-                            int width);
 void HalfFloatRow_MSA(const uint16_t* src,
                       uint16_t* dst,
                       float scale,
@@ -6288,6 +7168,7 @@
                     int width);
 
 void GaussRow_C(const uint32_t* src, uint16_t* dst, int width);
+void GaussRow_NEON(const uint32_t* src, uint16_t* dst, int width);
 void GaussCol_C(const uint16_t* src0,
                 const uint16_t* src1,
                 const uint16_t* src2,
@@ -6295,6 +7176,13 @@
                 const uint16_t* src4,
                 uint32_t* dst,
                 int width);
+void GaussCol_NEON(const uint16_t* src0,
+                   const uint16_t* src1,
+                   const uint16_t* src2,
+                   const uint16_t* src3,
+                   const uint16_t* src4,
+                   uint32_t* dst,
+                   int width);
 
 void ClampFloatToZero_SSE2(const float* src_x, float* dst_y, int width);
 
diff --git a/include/libyuv/row_sve.h b/include/libyuv/row_sve.h
new file mode 100644
index 0000000..14a4980
--- /dev/null
+++ b/include/libyuv/row_sve.h
@@ -0,0 +1,1789 @@
+/*
+ *  Copyright 2024 The LibYuv Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS. All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef INCLUDE_LIBYUV_ROW_SVE_H_
+#define INCLUDE_LIBYUV_ROW_SVE_H_
+
+#include "libyuv/row.h"
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__)
+
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+#define STREAMING_COMPATIBLE __arm_streaming_compatible
+#else  // defined(LIBYUV_DISABLE_SME) || !defined(CLANG_HAS_SME) ||
+       // !defined(__aarch64__)
+#define STREAMING_COMPATIBLE
+#endif  // !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) &&
+        // defined(__aarch64__)
+
+#define YUVTORGB_SVE_SETUP                          \
+  "ld1rb  {z28.b}, p0/z, [%[kUVCoeff], #0]      \n" \
+  "ld1rb  {z29.b}, p0/z, [%[kUVCoeff], #1]      \n" \
+  "ld1rb  {z30.b}, p0/z, [%[kUVCoeff], #2]      \n" \
+  "ld1rb  {z31.b}, p0/z, [%[kUVCoeff], #3]      \n" \
+  "ld1rh  {z24.h}, p0/z, [%[kRGBCoeffBias], #0] \n" \
+  "ld1rh  {z25.h}, p0/z, [%[kRGBCoeffBias], #2] \n" \
+  "ld1rh  {z26.h}, p0/z, [%[kRGBCoeffBias], #4] \n" \
+  "ld1rh  {z27.h}, p0/z, [%[kRGBCoeffBias], #6] \n"
+
+#define READYUV444_SVE                           \
+  "ld1b       {z0.h}, p1/z, [%[src_y]]       \n" \
+  "ld1b       {z1.h}, p1/z, [%[src_u]]       \n" \
+  "ld1b       {z2.h}, p1/z, [%[src_v]]       \n" \
+  "add        %[src_y], %[src_y], %[vl]      \n" \
+  "add        %[src_u], %[src_u], %[vl]      \n" \
+  "add        %[src_v], %[src_v], %[vl]      \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 448]     \n" \
+  "trn1       z0.b, z0.b, z0.b               \n" \
+  "prfm       pldl1keep, [%[src_v], 448]     \n"
+
+#define READYUV400_SVE                           \
+  "ld1b       {z0.h}, p1/z, [%[src_y]]       \n" \
+  "inch       %[src_y]                       \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "trn1       z0.b, z0.b, z0.b               \n"
+
+#define READYUV422_SVE                           \
+  "ld1b       {z0.h}, p1/z, [%[src_y]]       \n" \
+  "ld1b       {z1.s}, p1/z, [%[src_u]]       \n" \
+  "ld1b       {z2.s}, p1/z, [%[src_v]]       \n" \
+  "inch       %[src_y]                       \n" \
+  "incw       %[src_u]                       \n" \
+  "incw       %[src_v]                       \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "trn1       z0.b, z0.b, z0.b               \n" \
+  "trn1       z1.h, z1.h, z1.h               \n" \
+  "trn1       z2.h, z2.h, z2.h               \n"
+
+// Read twice as much data from YUV, putting the even elements from the Y data
+// in z0.h and odd elements in z1.h. U/V data is not duplicated, stored in
+// z2.h/z3.h.
+#define READYUV422_SVE_2X                        \
+  "ld1b       {z0.b}, p1/z, [%[src_y]]       \n" \
+  "ld1b       {z2.h}, p1/z, [%[src_u]]       \n" \
+  "ld1b       {z3.h}, p1/z, [%[src_v]]       \n" \
+  "incb       %[src_y]                       \n" \
+  "inch       %[src_u]                       \n" \
+  "inch       %[src_v]                       \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "trn2       z1.b, z0.b, z0.b               \n" \
+  "trn1       z0.b, z0.b, z0.b               \n"
+
+#define READI210_SVE                             \
+  "ld1h       {z3.h}, p1/z, [%[src_y]]       \n" \
+  "ld1h       {z1.s}, p1/z, [%[src_u]]       \n" \
+  "ld1h       {z2.s}, p1/z, [%[src_v]]       \n" \
+  "incb       %[src_y]                       \n" \
+  "inch       %[src_u]                       \n" \
+  "inch       %[src_v]                       \n" \
+  "lsl        z0.h, z3.h, #6                 \n" \
+  "trn1       z1.h, z1.h, z1.h               \n" \
+  "trn1       z2.h, z2.h, z2.h               \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "usra       z0.h, z3.h, #4                 \n" \
+  "uqshrnb    z1.b, z1.h, #2                 \n" \
+  "uqshrnb    z2.b, z2.h, #2                 \n"
+
+#define READP210_SVE                             \
+  "ld1h       {z0.h}, p1/z, [%[src_y]]       \n" \
+  "ld1h       {z1.h}, p2/z, [%[src_uv]]      \n" \
+  "incb       %[src_y]                       \n" \
+  "incb       %[src_uv]                      \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_uv], 256]    \n" \
+  "tbl        z1.b, {z1.b}, z22.b            \n"
+
+#define READI410_SVE                             \
+  "ld1h       {z3.h}, p1/z, [%[src_y]]       \n" \
+  "lsl        z0.h, z3.h, #6                 \n" \
+  "usra       z0.h, z3.h, #4                 \n" \
+  "ld1h       {z1.h}, p1/z, [%[src_u]]       \n" \
+  "ld1h       {z2.h}, p1/z, [%[src_v]]       \n" \
+  "incb       %[src_y]                       \n" \
+  "incb       %[src_u]                       \n" \
+  "incb       %[src_v]                       \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "uqshrnb    z1.b, z1.h, #2                 \n" \
+  "uqshrnb    z2.b, z2.h, #2                 \n"
+
+// We need different predicates for the UV components since we are reading
+// 32-bit (pairs of UV) elements rather than 16-bit Y elements.
+#define READP410_SVE                                    \
+  "ld1h       {z0.h}, p1/z, [%[src_y]]              \n" \
+  "ld1w       {z1.s}, p2/z, [%[src_uv]]             \n" \
+  "ld1w       {z2.s}, p3/z, [%[src_uv], #1, mul vl] \n" \
+  "incb       %[src_y]                              \n" \
+  "incb       %[src_uv], all, mul #2                \n" \
+  "prfm       pldl1keep, [%[src_y], 448]            \n" \
+  "prfm       pldl1keep, [%[src_uv], 256]           \n" \
+  "uzp2       z1.b, z1.b, z2.b                      \n"
+
+#define READI212_SVE                             \
+  "ld1h       {z3.h}, p1/z, [%[src_y]]       \n" \
+  "ld1h       {z1.s}, p1/z, [%[src_u]]       \n" \
+  "ld1h       {z2.s}, p1/z, [%[src_v]]       \n" \
+  "incb       %[src_y]                       \n" \
+  "inch       %[src_u]                       \n" \
+  "inch       %[src_v]                       \n" \
+  "lsl        z0.h, z3.h, #4                 \n" \
+  "trn1       z1.h, z1.h, z1.h               \n" \
+  "trn1       z2.h, z2.h, z2.h               \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "usra       z0.h, z3.h, #8                 \n" \
+  "uqshrnb    z1.b, z1.h, #4                 \n" \
+  "uqshrnb    z2.b, z2.h, #4                 \n"
+
+#define I400TORGB_SVE                                    \
+  "umulh      z18.h, z24.h, z0.h             \n" /* Y */ \
+  "movprfx    z16, z18                       \n"         \
+  "usqadd     z16.h, p0/m, z16.h, z4.h       \n" /* B */ \
+  "movprfx    z17, z18                       \n"         \
+  "usqadd     z17.h, p0/m, z17.h, z6.h       \n" /* G */ \
+  "usqadd     z18.h, p0/m, z18.h, z5.h       \n" /* R */
+
+// We need a different predicate for the UV component to handle the tail.
+// If there is a single element remaining then we want to load one Y element
+// but two UV elements.
+#define READNV_SVE_2X                                               \
+  "ld1b       {z0.b}, p1/z, [%[src_y]]       \n" /* Y0Y0 */         \
+  "ld1b       {z2.b}, p2/z, [%[src_uv]]      \n" /* U0V0 or V0U0 */ \
+  "incb       %[src_y]                       \n"                    \
+  "incb       %[src_uv]                      \n"                    \
+  "prfm       pldl1keep, [%[src_y], 448]     \n"                    \
+  "prfm       pldl1keep, [%[src_uv], 256]    \n"                    \
+  "trn2       z1.b, z0.b, z0.b               \n" /* YYYY */         \
+  "trn1       z0.b, z0.b, z0.b               \n" /* YYYY */
+
+// Like NVTORGB_SVE but U/V components are stored in widened .h elements of
+// z1/z2 rather than even/odd .b lanes of z1.
+#define I4XXTORGB_SVE                                     \
+  "umulh      z0.h, z24.h, z0.h              \n" /* Y */  \
+  "umullb     z6.h, z30.b, z1.b              \n"          \
+  "umullb     z4.h, z28.b, z1.b              \n" /* DB */ \
+  "umullb     z5.h, z29.b, z2.b              \n" /* DR */ \
+  "umlalb     z6.h, z31.b, z2.b              \n" /* DG */ \
+  "add        z17.h, z0.h, z26.h             \n" /* G */  \
+  "add        z16.h, z0.h, z4.h              \n" /* B */  \
+  "add        z18.h, z0.h, z5.h              \n" /* R */  \
+  "uqsub      z17.h, z17.h, z6.h             \n" /* G */  \
+  "uqsub      z16.h, z16.h, z25.h            \n" /* B */  \
+  "uqsub      z18.h, z18.h, z27.h            \n" /* R */
+
+// Like I4XXTORGB_SVE but U/V components are stored in even/odd .b lanes of z1
+// rather than widened .h elements of z1/z2.
+#define NVTORGB_SVE                                       \
+  "umulh      z0.h, z24.h, z0.h              \n" /* Y */  \
+  "umullb     z6.h, z30.b, z1.b              \n"          \
+  "umullb     z4.h, z28.b, z1.b              \n" /* DB */ \
+  "umullt     z5.h, z29.b, z1.b              \n" /* DR */ \
+  "umlalt     z6.h, z31.b, z1.b              \n" /* DG */ \
+  "add        z17.h, z0.h, z26.h             \n" /* G */  \
+  "add        z16.h, z0.h, z4.h              \n" /* B */  \
+  "add        z18.h, z0.h, z5.h              \n" /* R */  \
+  "uqsub      z17.h, z17.h, z6.h             \n" /* G */  \
+  "uqsub      z16.h, z16.h, z25.h            \n" /* B */  \
+  "uqsub      z18.h, z18.h, z27.h            \n" /* R */
+
+// The U/V component multiplies do not need to be duplicated in I422, we just
+// need to combine them with Y0/Y1 correctly.
+#define I422TORGB_SVE_2X                                  \
+  "umulh      z0.h, z24.h, z0.h              \n" /* Y0 */ \
+  "umulh      z1.h, z24.h, z1.h              \n" /* Y1 */ \
+  "umullb     z6.h, z30.b, z2.b              \n"          \
+  "umullb     z4.h, z28.b, z2.b              \n" /* DB */ \
+  "umullb     z5.h, z29.b, z3.b              \n" /* DR */ \
+  "umlalb     z6.h, z31.b, z3.b              \n" /* DG */ \
+                                                          \
+  "add        z17.h, z0.h, z26.h             \n" /* G0 */ \
+  "add        z21.h, z1.h, z26.h             \n" /* G1 */ \
+  "add        z16.h, z0.h, z4.h              \n" /* B0 */ \
+  "add        z20.h, z1.h, z4.h              \n" /* B1 */ \
+  "add        z18.h, z0.h, z5.h              \n" /* R0 */ \
+  "add        z22.h, z1.h, z5.h              \n" /* R1 */ \
+  "uqsub      z17.h, z17.h, z6.h             \n" /* G0 */ \
+  "uqsub      z21.h, z21.h, z6.h             \n" /* G1 */ \
+  "uqsub      z16.h, z16.h, z25.h            \n" /* B0 */ \
+  "uqsub      z20.h, z20.h, z25.h            \n" /* B1 */ \
+  "uqsub      z18.h, z18.h, z27.h            \n" /* R0 */ \
+  "uqsub      z22.h, z22.h, z27.h            \n" /* R1 */
+
+// clang-format off
+#define NVTORGB_SVE_2X(bt_u, bt_v)                        \
+  "umulh      z0.h, z24.h, z0.h              \n" /* Y0 */ \
+  "umulh      z1.h, z24.h, z1.h              \n" /* Y1 */ \
+  "umull" #bt_u " z6.h, z30.b, z2.b          \n"          \
+  "umull" #bt_u " z4.h, z28.b, z2.b          \n" /* DB */ \
+  "umull" #bt_v " z5.h, z29.b, z2.b          \n" /* DR */ \
+  "umlal" #bt_v " z6.h, z31.b, z2.b          \n" /* DG */ \
+                                                          \
+  "add        z17.h, z0.h, z26.h             \n" /* G0 */ \
+  "add        z21.h, z1.h, z26.h             \n" /* G1 */ \
+  "add        z16.h, z0.h, z4.h              \n" /* B0 */ \
+  "add        z20.h, z1.h, z4.h              \n" /* B1 */ \
+  "add        z18.h, z0.h, z5.h              \n" /* R0 */ \
+  "add        z22.h, z1.h, z5.h              \n" /* R1 */ \
+  "uqsub      z17.h, z17.h, z6.h             \n" /* G0 */ \
+  "uqsub      z21.h, z21.h, z6.h             \n" /* G1 */ \
+  "uqsub      z16.h, z16.h, z25.h            \n" /* B0 */ \
+  "uqsub      z20.h, z20.h, z25.h            \n" /* B1 */ \
+  "uqsub      z18.h, z18.h, z27.h            \n" /* R0 */ \
+  "uqsub      z22.h, z22.h, z27.h            \n" /* R1 */
+// clang-format on
+
+#define RGBTOARGB8_SVE_TOP_2X                        \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h */       \
+  "uqshl     z16.h, p0/m, z16.h, #2     \n" /* B0 */ \
+  "uqshl     z17.h, p0/m, z17.h, #2     \n" /* G0 */ \
+  "uqshl     z18.h, p0/m, z18.h, #2     \n" /* R0 */ \
+  "uqshl     z20.h, p0/m, z20.h, #2     \n" /* B1 */ \
+  "uqshl     z21.h, p0/m, z21.h, #2     \n" /* G1 */ \
+  "uqshl     z22.h, p0/m, z22.h, #2     \n" /* R1 */
+
+// Convert from 2.14 fixed point RGB to 8 bit ARGB, interleaving as BG and RA
+// pairs to allow us to use ST2 for storing rather than ST4.
+#define RGBTOARGB8_SVE                                    \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.b */ \
+  "uqshrnb     z16.b, z16.h, #6     \n" /* B0 */          \
+  "uqshrnb     z18.b, z18.h, #6     \n" /* R0 */          \
+  "uqshrnt     z16.b, z17.h, #6     \n" /* BG */          \
+  "trn1        z17.b, z18.b, z19.b  \n" /* RA */
+
+// Convert from 2.14 fixed point RGBA to 8 bit ARGB, interleaving as BG and RA
+// pairs to allow us to use ST2 for storing rather than ST4.
+#define RGBATOARGB8_SVE                                   \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.h */ \
+  "uqshrnb     z16.b, z16.h, #6     \n" /* B0 */          \
+  "uqshrnt     z16.b, z17.h, #6     \n" /* BG */          \
+  "uqshrnb     z17.b, z18.h, #6     \n" /* R0 */          \
+  "uqshrnt     z17.b, z19.h, #2     \n" /* RA */
+
+// Convert from 2.14 fixed point RGB to 8 bit RGBA, interleaving as AB and GR
+// pairs to allow us to use ST2 for storing rather than ST4.
+#define RGBTORGBA8_SVE                                    \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.b */ \
+  "uqshrnt     z19.b, z16.h, #6     \n" /* AB */          \
+  "uqshrnb     z20.b, z17.h, #6     \n" /* G0 */          \
+  "uqshrnt     z20.b, z18.h, #6     \n" /* GR */
+
+#define RGBTOARGB8_SVE_2X                                 \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.b */ \
+  "uqshrnb     z16.b, z16.h, #6     \n" /* B0 */          \
+  "uqshrnb     z17.b, z17.h, #6     \n" /* G0 */          \
+  "uqshrnb     z18.b, z18.h, #6     \n" /* R0 */          \
+  "uqshrnt     z16.b, z20.h, #6     \n" /* B1 */          \
+  "uqshrnt     z17.b, z21.h, #6     \n" /* G1 */          \
+  "uqshrnt     z18.b, z22.h, #6     \n" /* R1 */
+
+// Store AR30 elements. Inputs are 2.14 fixed point RGB. We expect z23 to be
+// populated with 0x3ff0 (0x3fff would also work) to saturate the R input
+// rather than needing a pair of shifts to saturate and then insert into the
+// correct position in the lane.
+#define STOREAR30_SVE                                                    \
+  "uqshl    z16.h, p0/m, z16.h, #2            \n" /* bbbbbbbbbbxxxxxx */ \
+  "uqshl    z17.h, p0/m, z17.h, #2            \n" /* ggggggggggxxxxxx */ \
+  "umin     z18.h, p0/m, z18.h, z23.h         \n" /* 00rrrrrrrrrrxxxx */ \
+  "orr      z18.h, z18.h, #0xc000             \n" /* 11rrrrrrrrrrxxxx */ \
+  "sri      z18.h, z17.h, #12                 \n" /* 11rrrrrrrrrrgggg */ \
+  "lsl      z17.h, z17.h, #4                  \n" /* ggggggxxxxxx0000 */ \
+  "sri      z17.h, z16.h, #6                  \n" /* ggggggbbbbbbbbbb */ \
+  "st2h     {z17.h, z18.h}, p1, [%[dst_ar30]] \n"                        \
+  "incb     %[dst_ar30], all, mul #2          \n"
+
+#define YUVTORGB_SVE_REGS                                                     \
+  "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z16", "z17", "z18", "z19", \
+      "z20", "z22", "z23", "z24", "z25", "z26", "z27", "z28", "z29", "z30",   \
+      "z31", "p0", "p1", "p2", "p3"
+
+static inline void I400ToARGBRow_SVE_SC(const uint8_t* src_y,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cnth     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"
+      "dup      z19.b, #255                             \n"  // Alpha
+      YUVTORGB_SVE_SETUP
+      "cmp      %w[width], %w[vl]                       \n"
+      "mov      z1.h, #128                              \n"  // U/V
+      "umullb   z6.h, z30.b, z1.b                       \n"
+      "umullb   z4.h, z28.b, z1.b                       \n"  // DB
+      "umullb   z5.h, z29.b, z1.b                       \n"  // DR
+      "mla      z6.h, p0/m, z31.h, z1.h                 \n"  // DG
+      "sub      z4.h, z4.h, z25.h                       \n"
+      "sub      z5.h, z5.h, z27.h                       \n"
+      "sub      z6.h, z26.h, z6.h                       \n"
+      "b.le     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "sub      %w[width], %w[width], %w[vl]            \n"
+      "1:                                               \n"  //
+      READYUV400_SVE I400TORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.gt     1b                                      \n"
+      "add      %w[width], %w[width], %w[vl]            \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "2:                                               \n"
+      "whilelt  p1.h, wzr, %w[width]                    \n"  //
+      READYUV400_SVE I400TORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I422ToARGBRow_SVE_SC(const uint8_t* src_y,
+                                        const uint8_t* src_u,
+                                        const uint8_t* src_v,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+      "incb     %[dst_argb], all, mul #4                \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I422ToRGB24Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_argb]] \n"
+      "incb     %[dst_argb], all, mul #3                \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_argb]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+#define RGB8TORGB565_SVE_FROM_TOP_2X                        \
+  "sri      z18.h, z17.h, #5     \n" /* rrrrrgggggg00000 */ \
+  "sri      z22.h, z21.h, #5     \n" /* rrrrrgggggg00000 */ \
+  "sri      z18.h, z16.h, #11    \n" /* rrrrrggggggbbbbb */ \
+  "sri      z22.h, z20.h, #11    \n" /* rrrrrggggggbbbbb */ \
+  "mov      z19.d, z22.d         \n"
+
+static inline void I422ToRGB565Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_rgb565,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"  //
+      RGB8TORGB565_SVE_FROM_TOP_2X
+      "st2h     {z18.h, z19.h}, p1, [%[dst]] \n"
+      "incb     %[dst], all, mul #2                     \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+          RGB8TORGB565_SVE_FROM_TOP_2X
+      "st2h     {z18.h, z19.h}, p1, [%[dst]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst] "+r"(dst_rgb565),                            // %[dst]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+#define RGB8TOARGB1555_SVE_FROM_TOP_2X                      \
+  "dup      z0.h, #0x8000        \n" /* 1000000000000000 */ \
+  "dup      z1.h, #0x8000        \n" /* 1000000000000000 */ \
+  "sri      z0.h, z18.h, #1      \n" /* 1rrrrrxxxxxxxxxx */ \
+  "sri      z1.h, z22.h, #1      \n" /* 1rrrrrxxxxxxxxxx */ \
+  "sri      z0.h, z17.h, #6      \n" /* 1rrrrrgggggxxxxx */ \
+  "sri      z1.h, z21.h, #6      \n" /* 1rrrrrgggggxxxxx */ \
+  "sri      z0.h, z16.h, #11     \n" /* 1rrrrrgggggbbbbb */ \
+  "sri      z1.h, z20.h, #11     \n" /* 1rrrrrgggggbbbbb */
+
+static inline void I422ToARGB1555Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb1555,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"  //
+      RGB8TOARGB1555_SVE_FROM_TOP_2X
+      "st2h     {z0.h, z1.h}, p1, [%[dst]] \n"
+      "incb     %[dst], all, mul #2                     \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+          RGB8TOARGB1555_SVE_FROM_TOP_2X
+      "st2h     {z0.h, z1.h}, p1, [%[dst]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst] "+r"(dst_argb1555),                          // %[dst]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+#define RGB8TOARGB4444_SVE_FROM_TOP_2X                      \
+  "dup      z0.h, #0xf000        \n" /* 1111000000000000 */ \
+  "dup      z1.h, #0xf000        \n" /* 1111000000000000 */ \
+  "sri      z0.h, z18.h, #4      \n" /* 1111rrrrxxxxxxxx */ \
+  "sri      z1.h, z22.h, #4      \n" /* 1111rrrrxxxxxxxx */ \
+  "sri      z0.h, z17.h, #8      \n" /* 1111rrrrggggxxxx */ \
+  "sri      z1.h, z21.h, #8      \n" /* 1111rrrrggggxxxx */ \
+  "sri      z0.h, z16.h, #12     \n" /* 1111rrrrggggbbbb */ \
+  "sri      z1.h, z20.h, #12     \n" /* 1111rrrrggggbbbb */
+
+static inline void I422ToARGB4444Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb4444,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"  //
+      RGB8TOARGB4444_SVE_FROM_TOP_2X
+      "st2h     {z0.h, z1.h}, p1, [%[dst]] \n"
+      "incb     %[dst], all, mul #2                     \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X I422TORGB_SVE_2X RGBTOARGB8_SVE_TOP_2X
+          RGB8TOARGB4444_SVE_FROM_TOP_2X
+      "st2h     {z0.h, z1.h}, p1, [%[dst]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst] "+r"(dst_argb4444),                          // %[dst]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I422ToRGBARow_SVE_SC(const uint8_t* src_y,
+                                        const uint8_t* src_u,
+                                        const uint8_t* src_v,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cnth     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.le     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE I4XXTORGB_SVE RGBTORGBA8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z19.h, z20.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.gt     1b                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      "whilelt  p1.h, wzr, %w[width]                    \n"  //
+      READYUV422_SVE I4XXTORGB_SVE RGBTORGBA8_SVE
+      "st2h     {z19.h, z20.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I422AlphaToARGBRow_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    const uint8_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV422_SVE_2X
+      "ld1b     {z19.b}, p1/z, [%[src_a]]               \n"
+      "add      %[src_a], %[src_a], %[vl]               \n"  // Alpha
+      I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+      "incb     %[dst_argb], all, mul #4                \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "cnth     %[vl]                                   \n"
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV422_SVE_2X
+      "ld1b     {z19.b}, p1/z, [%[src_a]]               \n"  // Alpha
+      I422TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [src_a] "+r"(src_a),                               // %[src_a]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I444AlphaToARGBRow_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    const uint8_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "cnth     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READYUV444_SVE
+      "ld1b     {z19.h}, p1/z, [%[src_a]]               \n"
+      "add      %[src_a], %[src_a], %[vl]               \n"  // Alpha
+      I4XXTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width]                    \n"  //
+      READYUV444_SVE
+      "ld1b     {z19.h}, p1/z, [%[src_a]]               \n"  // Alpha
+      I4XXTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [src_a] "+r"(src_a),                               // %[src_a]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void NV12ToARGBRow_SVE_SC(const uint8_t* src_y,
+                                        const uint8_t* src_uv,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cntb %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "ptrue    p2.b                                    \n"
+      "1:                                               \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(b, t) RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.b, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.b, wzr, %w[width_last_uv]            \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(b, t) RGBTOARGB8_SVE_2X
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+static inline void NV21ToARGBRow_SVE_SC(const uint8_t* src_y,
+                                        const uint8_t* src_vu,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cntb %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "ptrue    p2.b                                    \n"
+      "1:                                               \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(t, b) RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.b, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.b, wzr, %w[width_last_uv]            \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(t, b) RGBTOARGB8_SVE_2X
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_vu),                              // %[src_vu]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+static inline void NV12ToRGB24Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_uv,
+    uint8_t* dst_rgb24,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cntb %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "ptrue    p2.b                                    \n"
+      "1:                                               \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(b, t) RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_rgb24]]       \n"
+      "incb     %[dst_rgb24], all, mul #3               \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.b, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.b, wzr, %w[width_last_uv]            \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(b, t) RGBTOARGB8_SVE_2X
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_rgb24]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_rgb24] "+r"(dst_rgb24),                        // %[dst_rgb24]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+static inline void NV21ToRGB24Row_SVE_SC(
+    const uint8_t* src_y,
+    const uint8_t* src_vu,
+    uint8_t* dst_rgb24,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cntb %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "ptrue    p2.b                                    \n"
+      "1:                                               \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(t, b) RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_rgb24]]       \n"
+      "incb     %[dst_rgb24], all, mul #3               \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.b, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.b, wzr, %w[width_last_uv]            \n"  //
+      READNV_SVE_2X NVTORGB_SVE_2X(t, b) RGBTOARGB8_SVE_2X
+      "st3b     {z16.b, z17.b, z18.b}, p1, [%[dst_rgb24]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_vu),                              // %[src_vu]
+        [dst_rgb24] "+r"(dst_rgb24),                        // %[dst_rgb24]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+#define READYUY2_SVE                                        \
+  "ld1w       {z0.s}, p2/z, [%[src_yuy2]]    \n" /* YUYV */ \
+  "incb       %[src_yuy2]                    \n"            \
+  "prfm       pldl1keep, [%[src_yuy2], 448]  \n"            \
+  "tbl        z1.b, {z0.b}, z22.b            \n" /* UVUV */ \
+  "trn1       z0.b, z0.b, z0.b               \n" /* YYYY */
+
+static inline void YUY2ToARGBRow_SVE_SC(const uint8_t* src_yuy2,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint32_t nv_uv_start = 0x03010301U;
+  uint32_t nv_uv_step = 0x04040404U;
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"
+      "index    z22.s, %w[nv_uv_start], %w[nv_uv_step]  \n"
+      "dup      z19.b, #255                             \n"  // Alpha
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.h                                    \n"
+      "1:                                               \n"  //
+      READYUY2_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.h, wzr, %w[width_last_uv]            \n"  //
+      READYUY2_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_yuy2] "+r"(src_yuy2),                          // %[src_yuy2]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [nv_uv_start] "r"(nv_uv_start),                     // %[nv_uv_start]
+        [nv_uv_step] "r"(nv_uv_step),                       // %[nv_uv_step]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+#define READUYVY_SVE                                        \
+  "ld1w       {z0.s}, p2/z, [%[src_uyvy]]    \n" /* UYVY */ \
+  "incb       %[src_uyvy]                    \n"            \
+  "prfm       pldl1keep, [%[src_uyvy], 448]  \n"            \
+  "tbl        z1.b, {z0.b}, z22.b            \n" /* UVUV */ \
+  "trn2       z0.b, z0.b, z0.b               \n" /* YYYY */
+
+static inline void UYVYToARGBRow_SVE_SC(const uint8_t* src_uyvy,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint32_t nv_uv_start = 0x02000200U;
+  uint32_t nv_uv_step = 0x04040404U;
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"
+      "index    z22.s, %w[nv_uv_start], %w[nv_uv_step]  \n"
+      "dup      z19.b, #255                             \n"  // Alpha
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.h                                    \n"
+      "1:                                               \n"  //
+      READUYVY_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "2:                                               \n"
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.h, wzr, %w[width_last_uv]            \n"  //
+      READUYVY_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_uyvy] "+r"(src_uyvy),                          // %[src_yuy2]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [nv_uv_start] "r"(nv_uv_start),                     // %[nv_uv_start]
+        [nv_uv_step] "r"(nv_uv_step),                       // %[nv_uv_step]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS, "p2");
+}
+
+static inline void I210ToARGBRow_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI210_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI210_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I210AlphaToARGBRow_SVE_SC(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    const uint16_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                               \n"  //
+      YUVTORGB_SVE_SETUP
+      "subs     %w[width], %w[width], %w[vl]                       \n"
+      "b.lt     2f                                                 \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                               \n"
+      "1:                                                          \n"  //
+      READI210_SVE
+      "ld1h     {z19.h}, p1/z, [%[src_a]]                          \n"  //
+      I4XXTORGB_SVE
+      "incb     %[src_a]                                           \n"  //
+      RGBATOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]                       \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]                  \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2            \n"
+      "b.ge     1b                                                 \n"
+
+      "2:                                                          \n"
+      "adds     %w[width], %w[width], %w[vl]                       \n"
+      "b.eq     99f                                                \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]                        \n"  //
+      READI210_SVE
+      "ld1h     {z19.h}, p1/z, [%[src_a]]                          \n"  //
+      I4XXTORGB_SVE RGBATOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]                  \n"
+
+      "99:                                                         \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [src_a] "+r"(src_a),                                // %[src_a]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I210ToAR30Row_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_ar30,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  // The limit is used for saturating the 2.14 red channel in STOREAR30_SVE.
+  uint16_t limit = 0x3ff0;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z23.h, %w[limit]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI210_SVE I4XXTORGB_SVE STOREAR30_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI210_SVE I4XXTORGB_SVE STOREAR30_SVE
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_ar30] "+r"(dst_ar30),                          // %[dst_ar30]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [limit] "r"(limit)                                  // %[limit]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+// P210 has 10 bits in msb of 16 bit NV12 style layout.
+static inline void P210ToARGBRow_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_uv,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  uint32_t nv_uv_start = 0x03010301U;
+  uint32_t nv_uv_step = 0x04040404U;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "index    z22.s, %w[nv_uv_start], %w[nv_uv_step]  \n"
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.h                                    \n"
+      "1:                                               \n"  //
+      READP210_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.h, wzr, %w[width_last_uv]            \n"  //
+      READP210_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [nv_uv_start] "r"(nv_uv_start),                     // %[nv_uv_start]
+        [nv_uv_step] "r"(nv_uv_step),                       // %[nv_uv_step]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv)                  // %[width_last_uv]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void P210ToAR30Row_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_uv,
+                                        uint8_t* dst_ar30,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  int width_last_uv = width_last_y + (width_last_y & 1);
+  uint32_t nv_uv_start = 0x03010301U;
+  uint32_t nv_uv_step = 0x04040404U;
+  // The limit is used for saturating the 2.14 red channel in STOREAR30_SVE.
+  uint16_t limit = 0x3ff0;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "index    z22.s, %w[nv_uv_start], %w[nv_uv_step]  \n"
+      "dup      z23.h, %w[limit]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.h                                    \n"
+      "1:                                               \n"  //
+      READP210_SVE NVTORGB_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"  //
+      STOREAR30_SVE
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.h, wzr, %w[width_last_uv]            \n"  //
+      READP210_SVE NVTORGB_SVE STOREAR30_SVE
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_ar30] "+r"(dst_ar30),                          // %[dst_ar30]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [nv_uv_start] "r"(nv_uv_start),                     // %[nv_uv_start]
+        [nv_uv_step] "r"(nv_uv_step),                       // %[nv_uv_step]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [width_last_uv] "r"(width_last_uv),                 // %[width_last_uv]
+        [limit] "r"(limit)                                  // %[limit]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I410ToARGBRow_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI410_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI410_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I410AlphaToARGBRow_SVE_SC(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    const uint16_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                             \n"  //
+      YUVTORGB_SVE_SETUP
+      "cmp      %w[width], %w[vl]                                \n"
+      "subs     %w[width], %w[width], %w[vl]                     \n"
+      "b.lt     2f                                               \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                             \n"
+      "1:                                                        \n"  //
+      READI410_SVE
+      "ld1h     {z19.h}, p1/z, [%[src_a]]                        \n"  //
+      I4XXTORGB_SVE
+      "incb     %[src_a]                                         \n"  //
+      RGBATOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]                     \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]                \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2          \n"
+      "b.ge     1b                                               \n"
+
+      "2:                                                        \n"
+      "adds     %w[width], %w[width], %w[vl]                     \n"
+      "b.eq     99f                                              \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]                      \n"  //
+      READI410_SVE
+      "ld1h     {z19.h}, p1/z, [%[src_a]]                        \n"  //
+      I4XXTORGB_SVE RGBATOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]                \n"
+
+      "99:                                                       \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [src_a] "+r"(src_a),                                // %[src_a]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I410ToAR30Row_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_ar30,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  // The limit is used for saturating the 2.14 red channel in STOREAR30_SVE.
+  uint16_t limit = 0x3ff0;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z23.h, %w[limit]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI410_SVE I4XXTORGB_SVE STOREAR30_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI410_SVE I4XXTORGB_SVE STOREAR30_SVE
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_ar30] "+r"(dst_ar30),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [limit] "r"(limit)                                  // %[limit]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void P410ToARGBRow_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_uv,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.s                                    \n"
+      "ptrue    p3.s                                    \n"
+      "1:                                               \n"  //
+      READP410_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.s, wzr, %w[width_last_y]             \n"
+      "cntw     %x[vl]                                  \n"
+      "whilelt  p3.s, %w[vl], %w[width_last_y]          \n"  //
+      READP410_SVE NVTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void P410ToAR30Row_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_uv,
+                                        uint8_t* dst_ar30,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  // The limit is used for saturating the 2.14 red channel in STOREAR30_SVE.
+  uint16_t limit = 0x3ff0;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z23.h, %w[limit]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "ptrue    p2.s                                    \n"
+      "ptrue    p3.s                                    \n"
+      "1:                                               \n"  //
+      READP410_SVE NVTORGB_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"  //
+      STOREAR30_SVE
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"
+      "whilelt  p2.s, wzr, %w[width_last_y]             \n"
+      "cntw     %x[vl]                                  \n"
+      "whilelt  p3.s, %w[vl], %w[width_last_y]          \n"  //
+      READP410_SVE NVTORGB_SVE STOREAR30_SVE
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_uv] "+r"(src_uv),                              // %[src_uv]
+        [dst_ar30] "+r"(dst_ar30),                          // %[dst_ar30]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [limit] "r"(limit)                                  // %[limit]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I212ToAR30Row_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_ar30,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  // The limit is used for saturating the 2.14 red channel in STOREAR30_SVE.
+  uint16_t limit = 0x3ff0;
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z23.h, %w[limit]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI212_SVE I4XXTORGB_SVE STOREAR30_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI212_SVE I4XXTORGB_SVE STOREAR30_SVE
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_ar30] "+r"(dst_ar30),                          // %[dst_ar30]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y),                   // %[width_last_y]
+        [limit] "r"(limit)                                  // %[limit]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+static inline void I212ToARGBRow_SVE_SC(const uint16_t* src_y,
+                                        const uint16_t* src_u,
+                                        const uint16_t* src_v,
+                                        uint8_t* dst_argb,
+                                        const struct YuvConstants* yuvconstants,
+                                        int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm("cnth %0" : "=r"(vl));
+  int width_last_y = width & (vl - 1);
+  asm volatile(
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READI212_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width_last_y]             \n"  //
+      READI212_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                                // %[src_y]
+        [src_u] "+r"(src_u),                                // %[src_u]
+        [src_v] "+r"(src_v),                                // %[src_v]
+        [dst_argb] "+r"(dst_argb),                          // %[dst_argb]
+        [width] "+r"(width)                                 // %[width]
+      : [vl] "r"(vl),                                       // %[vl]
+        [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
+        [width_last_y] "r"(width_last_y)                    // %[width_last_y]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+#define CONVERT8TO8_SVE                                  \
+  "ld1b        {z0.b}, p0/z, [%[src]]                \n" \
+  "ld1b        {z1.b}, p1/z, [%[src], #1, mul vl]    \n" \
+  "incb        %[src], all, mul #2                   \n" \
+  "subs        %w[width], %w[width], %w[vl], lsl #1  \n" \
+  "umulh       z0.b, z0.b, z2.b                      \n" \
+  "umulh       z1.b, z1.b, z2.b                      \n" \
+  "prfm        pldl1keep, [%[src], 448]              \n" \
+  "add         z0.b, z0.b, z3.b                      \n" \
+  "add         z1.b, z1.b, z3.b                      \n" \
+  "st1b        {z0.b}, p0, [%[dst]]                  \n" \
+  "st1b        {z1.b}, p1, [%[dst], #1, mul vl]      \n" \
+  "incb        %[dst], all, mul #2                   \n"
+
+static inline void Convert8To8Row_SVE_SC(const uint8_t* src_y,
+                                         uint8_t* dst_y,
+                                         int scale,
+                                         int bias,
+                                         int width) STREAMING_COMPATIBLE {
+  uint64_t vl;
+  asm volatile(
+      "dup      z2.b, %w[scale]                         \n"
+      "dup      z3.b, %w[bias]                          \n"
+      "cntb     %[vl]                                   \n"
+      "subs     %w[width], %w[width], %w[vl], lsl #1    \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with all-true predicates to avoid predicate
+      // generation overhead.
+      "ptrue    p0.b                                    \n"
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      CONVERT8TO8_SVE
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl], lsl #1    \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate predicates for the final iteration to deal with the tail.
+      "whilelt     p0.b, wzr, %w[width]                 \n"
+      "whilelt     p1.b, %w[vl], %w[width]              \n"  //
+      CONVERT8TO8_SVE
+
+      "99:                                              \n"
+      : [src] "+r"(src_y),    // %[src]
+        [dst] "+r"(dst_y),    // %[dst]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      : [scale] "r"(scale),   // %[scale]
+        [bias] "r"(bias)      // %[bias]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "p0", "p1");
+}
+
+#endif  // !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__)
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
+
+#endif  // INCLUDE_LIBYUV_ROW_SVE_H_
diff --git a/include/libyuv/scale.h b/include/libyuv/scale.h
index bfe4a34..1a8cb3d 100644
--- a/include/libyuv/scale.h
+++ b/include/libyuv/scale.h
@@ -287,6 +287,21 @@
               int dst_height,
               enum FilterMode filtering);
 
+LIBYUV_API
+int NV24Scale(const uint8_t* src_y,
+              int src_stride_y,
+              const uint8_t* src_uv,
+              int src_stride_uv,
+              int src_width,
+              int src_height,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_uv,
+              int dst_stride_uv,
+              int dst_width,
+              int dst_height,
+              enum FilterMode filtering);
+
 #ifdef __cplusplus
 // Legacy API.  Deprecated.
 LIBYUV_API
diff --git a/include/libyuv/scale_row.h b/include/libyuv/scale_row.h
index 02ed61c..eef68eb 100644
--- a/include/libyuv/scale_row.h
+++ b/include/libyuv/scale_row.h
@@ -12,6 +12,7 @@
 #define INCLUDE_LIBYUV_SCALE_ROW_H_
 
 #include "libyuv/basic_types.h"
+#include "libyuv/cpu_support.h"
 #include "libyuv/scale.h"
 
 #ifdef __cplusplus
@@ -19,46 +20,11 @@
 extern "C" {
 #endif
 
-#if defined(__pnacl__) || defined(__CLR_VER) ||            \
-    (defined(__native_client__) && defined(__x86_64__)) || \
-    (defined(__i386__) && !defined(__SSE__) && !defined(__clang__))
-#define LIBYUV_DISABLE_X86
-#endif
-#if defined(__native_client__)
-#define LIBYUV_DISABLE_NEON
-#endif
-// MemorySanitizer does not support assembly code yet. http://crbug.com/344505
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_NEON)
-#define LIBYUV_DISABLE_NEON
-#endif
-#if __has_feature(memory_sanitizer) && !defined(LIBYUV_DISABLE_X86)
-#define LIBYUV_DISABLE_X86
-#endif
-#endif
-// GCC >= 4.7.0 required for AVX2.
-#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
-#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
-#define GCC_HAS_AVX2 1
-#endif  // GNUC >= 4.7
-#endif  // __GNUC__
-
-// clang >= 3.4.0 required for AVX2.
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
-#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
-#define CLANG_HAS_AVX2 1
-#endif  // clang >= 3.4
-#endif  // __clang__
-
-// Visual C 2012 required for AVX2.
-#if defined(_M_IX86) && !defined(__clang__) && defined(_MSC_VER) && \
-    _MSC_VER >= 1700
-#define VISUALC_HAS_AVX2 1
-#endif  // VisualStudio >= 2012
-
 // The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
-    (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&                             \
+    (defined(_M_IX86) ||                                        \
+     (defined(__x86_64__) && !defined(LIBYUV_ENABLE_ROWWIN)) || \
+     defined(__i386__))
 #define HAS_FIXEDDIV1_X86
 #define HAS_FIXEDDIV_X86
 #define HAS_SCALEADDROW_SSE2
@@ -77,7 +43,9 @@
 
 // The following are available for gcc/clang x86 platforms:
 // TODO(fbarchard): Port to Visual C
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 #define HAS_SCALEUVROWDOWN2BOX_SSSE3
 #define HAS_SCALEROWUP2_LINEAR_SSE2
 #define HAS_SCALEROWUP2_LINEAR_SSSE3
@@ -152,6 +120,22 @@
 #define HAS_SCALEUVROWUP2_BILINEAR_16_NEON
 #endif
 
+// The following are available on AArch64 Neon platforms:
+#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
+#define HAS_SCALEROWDOWN2_16_NEON
+#endif
+
+// The following are available on AArch64 SME platforms:
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+#define HAS_SCALEARGBROWDOWN2_SME
+#define HAS_SCALEROWDOWN2_16_SME
+#define HAS_SCALEROWDOWN2_SME
+#define HAS_SCALEUVROWDOWN2BOX_SME
+#define HAS_SCALEUVROWDOWN2LINEAR_SME
+#define HAS_SCALEUVROWDOWN2_SME
+#endif
+
 #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa)
 #define HAS_SCALEADDROW_MSA
 #define HAS_SCALEARGBCOLS_MSA
@@ -178,36 +162,49 @@
 #define HAS_SCALEROWDOWN34_LSX
 #endif
 
-#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector)
-#define HAS_SCALEADDROW_RVV
-// TODO: Test ScaleARGBRowDownEven_RVV and enable it
-// #define HAS_SCALEARGBROWDOWNEVEN_RVV
+// The following are available on RVV with 64 bit elements
+// TODO: Update compiler to support 64 bit
+#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) && \
+    defined(__riscv_zve64x)
 #define HAS_SCALEUVROWDOWN4_RVV
-#define HAS_SCALEUVROWDOWNEVEN_RVV
-#if __riscv_v_intrinsic == 11000
 #define HAS_SCALEARGBROWDOWN2_RVV
+#endif
+
+// The following are available on RVV 1.1
+// TODO: Port to RVV 1.2
+#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) && \
+    defined(__riscv_v_intrinsic) && __riscv_v_intrinsic == 11000
+#define HAS_SCALEROWDOWN34_0_BOX_RVV
+#define HAS_SCALEROWDOWN34_1_BOX_RVV
+#define HAS_SCALEROWDOWN38_2_BOX_RVV
+#define HAS_SCALEROWDOWN38_3_BOX_RVV
+#define HAS_SCALEUVROWUP2_BILINEAR_RVV
+#define HAS_SCALEUVROWUP2_LINEAR_RVV
+#define HAS_SCALEROWDOWN34_RVV
+#define HAS_SCALEROWDOWN38_RVV
+#define HAS_SCALEROWUP2_BILINEAR_RVV
+#define HAS_SCALEROWUP2_LINEAR_RVV
+#endif
+
+// The following are available on RVV
+#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) && \
+    defined(__riscv_v_intrinsic) && __riscv_v_intrinsic == 11000
+#define HAS_SCALEARGBFILTERCOLS_RVV
 #define HAS_SCALEARGBROWDOWN2BOX_RVV
 #define HAS_SCALEARGBROWDOWN2LINEAR_RVV
 #define HAS_SCALEARGBROWDOWNEVENBOX_RVV
-#define HAS_SCALEROWDOWN2_RVV
 #define HAS_SCALEROWDOWN2BOX_RVV
+#define HAS_SCALEADDROW_RVV
+// TODO: Test ScaleARGBRowDownEven_RVV and enable it
+// #define HAS_SCALEARGBROWDOWNEVEN_RVV
+#define HAS_SCALEUVROWDOWNEVEN_RVV
+#define HAS_SCALEROWDOWN2_RVV
 #define HAS_SCALEROWDOWN2LINEAR_RVV
-#define HAS_SCALEROWDOWN34_0_BOX_RVV
-#define HAS_SCALEROWDOWN34_1_BOX_RVV
-#define HAS_SCALEROWDOWN34_RVV
-#define HAS_SCALEROWDOWN38_2_BOX_RVV
-#define HAS_SCALEROWDOWN38_3_BOX_RVV
-#define HAS_SCALEROWDOWN38_RVV
 #define HAS_SCALEROWDOWN4_RVV
 #define HAS_SCALEROWDOWN4BOX_RVV
-#define HAS_SCALEROWUP2_BILINEAR_RVV
-#define HAS_SCALEROWUP2_LINEAR_RVV
 #define HAS_SCALEUVROWDOWN2_RVV
 #define HAS_SCALEUVROWDOWN2BOX_RVV
 #define HAS_SCALEUVROWDOWN2LINEAR_RVV
-#define HAS_SCALEUVROWUP2_BILINEAR_RVV
-#define HAS_SCALEUVROWUP2_LINEAR_RVV
-#endif
 #endif
 
 // Scale ARGB vertically with bilinear interpolation.
@@ -958,6 +955,11 @@
                            int dst_width,
                            int x,
                            int dx);
+void ScaleARGBFilterCols_RVV(uint8_t* dst_argb,
+                             const uint8_t* src_argb,
+                             int dst_width,
+                             int x,
+                             int dx);
 
 // ARGB Row functions
 void ScaleARGBRowDown2_SSE2(const uint8_t* src_argb,
@@ -976,14 +978,26 @@
                             ptrdiff_t src_stride,
                             uint8_t* dst,
                             int dst_width);
+void ScaleARGBRowDown2_SME(const uint8_t* src_ptr,
+                           ptrdiff_t src_stride,
+                           uint8_t* dst,
+                           int dst_width);
 void ScaleARGBRowDown2Linear_NEON(const uint8_t* src_argb,
                                   ptrdiff_t src_stride,
                                   uint8_t* dst_argb,
                                   int dst_width);
+void ScaleARGBRowDown2Linear_SME(const uint8_t* src_argb,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst_argb,
+                                 int dst_width);
 void ScaleARGBRowDown2Box_NEON(const uint8_t* src_ptr,
                                ptrdiff_t src_stride,
                                uint8_t* dst,
                                int dst_width);
+void ScaleARGBRowDown2Box_SME(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst,
+                              int dst_width);
 void ScaleARGBRowDown2_RVV(const uint8_t* src_argb,
                            ptrdiff_t src_stride,
                            uint8_t* dst_argb,
@@ -1180,14 +1194,26 @@
                           ptrdiff_t src_stride,
                           uint8_t* dst,
                           int dst_width);
+void ScaleUVRowDown2_SME(const uint8_t* src_ptr,
+                         ptrdiff_t src_stride,
+                         uint8_t* dst,
+                         int dst_width);
 void ScaleUVRowDown2Linear_NEON(const uint8_t* src_ptr,
                                 ptrdiff_t src_stride,
                                 uint8_t* dst_uv,
                                 int dst_width);
+void ScaleUVRowDown2Linear_SME(const uint8_t* src_ptr,
+                               ptrdiff_t src_stride,
+                               uint8_t* dst_uv,
+                               int dst_width);
 void ScaleUVRowDown2Box_NEON(const uint8_t* src_ptr,
                              ptrdiff_t src_stride,
                              uint8_t* dst,
                              int dst_width);
+void ScaleUVRowDown2Box_SME(const uint8_t* src_ptr,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            int dst_width);
 void ScaleUVRowDown2_MSA(const uint8_t* src_ptr,
                          ptrdiff_t src_stride,
                          uint8_t* dst_uv,
@@ -1429,21 +1455,55 @@
                                         int dst_width);
 
 // ScaleRowDown2Box also used by planar functions
-// NEON downscalers with interpolation.
-
-// Note - not static due to reuse in convert for 444 to 420.
+// NEON/SME downscalers with interpolation.
 void ScaleRowDown2_NEON(const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
                         uint8_t* dst,
                         int dst_width);
+void ScaleRowDown2_SME(const uint8_t* src_ptr,
+                       ptrdiff_t src_stride,
+                       uint8_t* dst,
+                       int dst_width);
+void ScaleRowDown2_16_NEON(const uint16_t* src_ptr,
+                           ptrdiff_t src_stride,
+                           uint16_t* dst,
+                           int dst_width);
+void ScaleRowDown2_16_SME(const uint16_t* src_ptr,
+                          ptrdiff_t src_stride,
+                          uint16_t* dst,
+                          int dst_width);
 void ScaleRowDown2Linear_NEON(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst,
                               int dst_width);
+void ScaleRowDown2Linear_SME(const uint8_t* src_ptr,
+                             ptrdiff_t src_stride,
+                             uint8_t* dst,
+                             int dst_width);
+void ScaleRowDown2Linear_16_NEON(const uint16_t* src_ptr,
+                                 ptrdiff_t src_stride,
+                                 uint16_t* dst,
+                                 int dst_width);
+void ScaleRowDown2Linear_16_SME(const uint16_t* src_ptr,
+                                ptrdiff_t src_stride,
+                                uint16_t* dst,
+                                int dst_width);
 void ScaleRowDown2Box_NEON(const uint8_t* src_ptr,
                            ptrdiff_t src_stride,
                            uint8_t* dst,
                            int dst_width);
+void ScaleRowDown2Box_SME(const uint8_t* src_ptr,
+                          ptrdiff_t src_stride,
+                          uint8_t* dst,
+                          int dst_width);
+void ScaleRowDown2Box_16_NEON(const uint16_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint16_t* dst,
+                              int dst_width);
+void ScaleRowDown2Box_16_SME(const uint16_t* src_ptr,
+                             ptrdiff_t src_stride,
+                             uint16_t* dst,
+                             int dst_width);
 
 void ScaleRowDown4_NEON(const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
diff --git a/include/libyuv/version.h b/include/libyuv/version.h
index a9c5440..2b72bc4 100644
--- a/include/libyuv/version.h
+++ b/include/libyuv/version.h
@@ -11,6 +11,6 @@
 #ifndef INCLUDE_LIBYUV_VERSION_H_
 #define INCLUDE_LIBYUV_VERSION_H_
 
-#define LIBYUV_VERSION 1883
+#define LIBYUV_VERSION 1907
 
 #endif  // INCLUDE_LIBYUV_VERSION_H_
diff --git a/infra/config/PRESUBMIT.py b/infra/config/PRESUBMIT.py
index f79e08a..0aa465e 100644
--- a/infra/config/PRESUBMIT.py
+++ b/infra/config/PRESUBMIT.py
@@ -6,8 +6,12 @@
 
 
 def CheckChangeOnUpload(input_api, output_api):
-  return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api)
+    return input_api.canned_checks.CheckChangedLUCIConfigs(
+        input_api, output_api
+    )
 
 
 def CheckChangeOnCommit(input_api, output_api):
-  return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api)
+    return input_api.canned_checks.CheckChangedLUCIConfigs(
+        input_api, output_api
+    )
diff --git a/infra/config/commit-queue.cfg b/infra/config/commit-queue.cfg
index 4a8d77f..640b530 100644
--- a/infra/config/commit-queue.cfg
+++ b/infra/config/commit-queue.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see Config message:
-#   https://luci-config.appspot.com/schemas/projects:commit-queue.cfg
+#   https://config.luci.app/schemas/projects:commit-queue.cfg
 
 cq_status_host: "chromium-cq-status.appspot.com"
 submit_options {
@@ -91,6 +91,7 @@
       }
       builders {
         name: "libyuv/try/linux_msan"
+        experiment_percentage: 100
       }
       builders {
         name: "libyuv/try/linux_rel"
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 7415851..c2e6177 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see BuildbucketCfg message:
-#   https://luci-config.appspot.com/schemas/projects:buildbucket.cfg
+#   https://config.luci.app/schemas/projects:buildbucket.cfg
 
 buckets {
   name: "ci"
@@ -20,7 +20,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -50,7 +50,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -80,7 +80,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -194,7 +194,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -224,7 +224,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -254,7 +254,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -284,7 +284,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -314,7 +314,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -344,7 +344,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -374,7 +374,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -404,7 +404,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -434,7 +434,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -464,7 +464,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -494,7 +494,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.ci"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -904,6 +904,9 @@
       }
     }
   }
+  constraints {
+    pools: "luci.flex.ci"
+  }
 }
 buckets {
   name: "cron"
@@ -1049,7 +1052,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1079,7 +1082,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1167,7 +1170,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1197,7 +1200,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1227,7 +1230,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1257,7 +1260,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1287,7 +1290,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1317,7 +1320,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1347,7 +1350,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1377,7 +1380,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1494,7 +1497,7 @@
       swarming_tags: "vpython:native-python-wrapper"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
+      dimensions: "os:Ubuntu-22.04"
       dimensions: "pool:luci.flex.try"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
@@ -1701,4 +1704,8 @@
       }
     }
   }
+  constraints {
+    pools: "luci.flex.try"
+    service_accounts: "libyuv-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+  }
 }
diff --git a/infra/config/luci-logdog.cfg b/infra/config/luci-logdog.cfg
index adc75be..01a3912 100644
--- a/infra/config/luci-logdog.cfg
+++ b/infra/config/luci-logdog.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see ProjectConfig message:
-#   https://luci-config.appspot.com/schemas/projects:luci-logdog.cfg
+#   https://config.luci.app/schemas/projects:luci-logdog.cfg
 
 reader_auth_groups: "all"
 writer_auth_groups: "luci-logdog-chromium-writers"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index baf786f..cde1848 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see Project message:
-#   https://luci-config.appspot.com/schemas/projects:luci-milo.cfg
+#   https://config.luci.app/schemas/projects:luci-milo.cfg
 
 consoles {
   id: "main"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 0ec5dd0..33bd6a7 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see ProjectConfig message:
-#   https://luci-config.appspot.com/schemas/projects:luci-scheduler.cfg
+#   https://config.luci.app/schemas/projects:luci-scheduler.cfg
 
 job {
   id: "Android ARM64 Debug"
diff --git a/infra/config/main.star b/infra/config/main.star
index e83afe4..09a12b6 100755
--- a/infra/config/main.star
+++ b/infra/config/main.star
@@ -21,12 +21,6 @@
 # Use LUCI Scheduler BBv2 names and add Scheduler realms configs.
 lucicfg.enable_experiment("crbug.com/1182002")
 
-luci.builder.defaults.experiments.set(
-    {
-        "luci.recipes.use_python3": 100,
-    },
-)
-
 lucicfg.config(
     lint_checks = ["default"],
     config_dir = ".",
@@ -175,6 +169,9 @@
 
 luci.bucket(
     name = "ci",
+    constraints = luci.bucket_constraints(
+        pools = ["luci.flex.ci"],
+    ),
 )
 luci.bucket(
     name = "try",
@@ -184,6 +181,12 @@
             "service-account-cq",
         ]),
     ],
+    constraints = luci.bucket_constraints(
+        pools = ["luci.flex.try"],
+        service_accounts = [
+            "libyuv-try-builder@chops-service-accounts.iam.gserviceaccount.com",
+        ],
+    ),
 )
 luci.bucket(
     name = "cron",
@@ -197,7 +200,7 @@
     elif os == "win":
         return {"os": "Windows-10", "cores": "8", "cpu": "x86-64"}
     elif os == "linux":
-        return {"os": "Ubuntu-18.04", "cores": "8", "cpu": "x86-64"}
+        return {"os": "Ubuntu-22.04", "cores": "8", "cpu": "x86-64"}
     return {}
 
 def libyuv_ci_builder(name, dimensions, properties, triggered_by):
@@ -327,7 +330,8 @@
 try_builder("linux", "linux")
 try_builder("linux_asan", "linux")
 try_builder("linux_gcc", "linux", experiment_percentage = 100)
-try_builder("linux_msan", "linux")
+# TODO(libyuv:388428508): Make linux_msan not experimental.
+try_builder("linux_msan", "linux", experiment_percentage = 100)
 try_builder("linux_rel", "linux")
 try_builder("linux_tsan2", "linux")
 try_builder("linux_ubsan", "linux")
diff --git a/infra/config/project.cfg b/infra/config/project.cfg
index 3c32711..59b1c24 100644
--- a/infra/config/project.cfg
+++ b/infra/config/project.cfg
@@ -2,12 +2,12 @@
 # Do not modify manually.
 #
 # For the schema of this file, see ProjectCfg message:
-#   https://luci-config.appspot.com/schemas/projects:project.cfg
+#   https://config.luci.app/schemas/projects:project.cfg
 
 name: "libyuv"
 access: "group:all"
 lucicfg {
-  version: "1.39.14"
+  version: "1.43.16"
   package_dir: "."
   config_dir: "."
   entry_point: "main.star"
diff --git a/infra/config/realms.cfg b/infra/config/realms.cfg
index 16ffaac..e275bdd 100644
--- a/infra/config/realms.cfg
+++ b/infra/config/realms.cfg
@@ -2,7 +2,7 @@
 # Do not modify manually.
 #
 # For the schema of this file, see RealmsCfg message:
-#   https://luci-config.appspot.com/schemas/projects:realms.cfg
+#   https://config.luci.app/schemas/projects:realms.cfg
 
 realms {
   name: "@root"
diff --git a/libyuv.gni b/libyuv.gni
index 343160c..3334df7 100644
--- a/libyuv.gni
+++ b/libyuv.gni
@@ -18,12 +18,17 @@
   libyuv_use_neon =
       current_cpu == "arm64" ||
       (current_cpu == "arm" && (arm_use_neon || arm_optionally_use_neon))
+  libyuv_use_sve = current_cpu == "arm64"
+
+  # Restrict to (is_linux || is_android) to work around undefined symbol linker
+  # errors on Fuchsia, macOS, and compilation errors on Windows.
+  # TODO: bug 359006069 - Remove the restriction after the linker and
+  # compilation errors are fixed.
+  libyuv_use_sme = current_cpu == "arm64" && (is_linux || is_android)
   libyuv_use_msa =
       (current_cpu == "mips64el" || current_cpu == "mipsel") && mips_use_msa
   libyuv_use_mmi =
       (current_cpu == "mips64el" || current_cpu == "mipsel") && mips_use_mmi
-  libyuv_use_lsx =
-      (current_cpu == "loong64") && loongarch64_use_lsx
-  libyuv_use_lasx =
-      (current_cpu == "loong64") && loongarch64_use_lasx
+  libyuv_use_lsx = current_cpu == "loong64" && loongarch64_use_lsx
+  libyuv_use_lasx = current_cpu == "loong64" && loongarch64_use_lasx
 }
diff --git a/libyuv.gypi b/libyuv.gypi
index 48936aa..74fa0fe 100644
--- a/libyuv.gypi
+++ b/libyuv.gypi
@@ -13,11 +13,13 @@
       'include/libyuv.h',
       'include/libyuv/basic_types.h',
       'include/libyuv/compare.h',
+      'include/libyuv/compare_row.h',
       'include/libyuv/convert.h',
       'include/libyuv/convert_argb.h',
       'include/libyuv/convert_from.h',
       'include/libyuv/convert_from_argb.h',
       'include/libyuv/cpu_id.h',
+      'include/libyuv/loongson_intrinsics.h',
       'include/libyuv/macros_msa.h',
       'include/libyuv/mjpeg_decoder.h',
       'include/libyuv/planar_functions.h',
diff --git a/pylintrc b/pylintrc
index b8bea33..57be7df 100644
--- a/pylintrc
+++ b/pylintrc
@@ -13,5 +13,37 @@
 
 [FORMAT]
 
-# We use two spaces for indents, instead of the usual four spaces or tab.
-indent-string='  '
+# Maximum number of characters on a single line.
+max-line-length=79
+
+# We use four spaces for indents.
+indent-string='    '
+
+[BASIC]
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct method names.
+method-rgx=([a-z_][a-z0-9_]{2,}|setUp|tearDown)$
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
diff --git a/riscv_script/riscv-clang.cmake b/riscv_script/riscv-clang.cmake
index e287941..35888ae 100644
--- a/riscv_script/riscv-clang.cmake
+++ b/riscv_script/riscv-clang.cmake
@@ -43,6 +43,7 @@
     list(APPEND RISCV_COMPILER_FLAGS "-march=rv64gc")
   endif()
 endif()
+add_compile_options("-Wuninitialized")
 message(STATUS "RISCV_COMPILER_FLAGS: ${RISCV_COMPILER_FLAGS}")
 
 set(CMAKE_C_FLAGS             "${RISCV_COMPILER_FLAGS} ${CMAKE_C_FLAGS}")
diff --git a/source/compare.cc b/source/compare.cc
index 50a736b..3ce4cfe 100644
--- a/source/compare.cc
+++ b/source/compare.cc
@@ -44,6 +44,11 @@
     HashDjb2_SSE = HashDjb2_AVX2;
   }
 #endif
+#if defined(HAS_HASHDJB2_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    HashDjb2_SSE = HashDjb2_NEON;
+  }
+#endif
 
   while (count >= (uint64_t)kBlockSize) {
     seed = HashDjb2_SSE(src, kBlockSize, seed);
@@ -134,6 +139,11 @@
     HammingDistance = HammingDistance_NEON;
   }
 #endif
+#if defined(HAS_HAMMINGDISTANCE_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    HammingDistance = HammingDistance_NEON_DotProd;
+  }
+#endif
 #if defined(HAS_HAMMINGDISTANCE_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     HammingDistance = HammingDistance_SSSE3;
@@ -194,6 +204,11 @@
     SumSquareError = SumSquareError_NEON;
   }
 #endif
+#if defined(HAS_SUMSQUAREERROR_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    SumSquareError = SumSquareError_NEON_DotProd;
+  }
+#endif
 #if defined(HAS_SUMSQUAREERROR_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
     // Note only used for multiples of 16 so count is not checked.
diff --git a/source/compare_gcc.cc b/source/compare_gcc.cc
index 33cbe25..33a725e 100644
--- a/source/compare_gcc.cc
+++ b/source/compare_gcc.cc
@@ -19,13 +19,17 @@
 #endif
 
 // This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
+
+// "memory" clobber prevents the reads from being removed
 
 #if defined(__x86_64__)
 uint32_t HammingDistance_SSE42(const uint8_t* src_a,
                                const uint8_t* src_b,
                                int count) {
-  uint64_t diff = 0u;
+  uint64_t diff;
 
   asm volatile(
       "xor         %3,%3                         \n"
@@ -35,7 +39,7 @@
 
       // Process 32 bytes per loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "mov         (%0),%%rcx                    \n"
       "mov         0x8(%0),%%rdx                 \n"
       "xor         (%1),%%rcx                    \n"
@@ -63,9 +67,9 @@
       : "+r"(src_a),  // %0
         "+r"(src_b),  // %1
         "+r"(count),  // %2
-        "=r"(diff)    // %3
+        "=&r"(diff)   // %3
       :
-      : "memory", "cc", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10");
+      : "cc", "memory", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10");
 
   return (uint32_t)(diff);
 }
@@ -78,7 +82,7 @@
   asm volatile(
       // Process 16 bytes per loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "mov         (%0),%%ecx                    \n"
       "mov         0x4(%0),%%edx                 \n"
       "xor         (%1),%%ecx                    \n"
@@ -104,7 +108,7 @@
         "+r"(count),  // %2
         "+r"(diff)    // %3
       :
-      : "memory", "cc", "ecx", "edx");
+      : "cc", "memory", "ecx", "edx");
 
   return diff;
 }
@@ -117,7 +121,7 @@
 uint32_t HammingDistance_SSSE3(const uint8_t* src_a,
                                const uint8_t* src_b,
                                int count) {
-  uint32_t diff = 0u;
+  uint32_t diff;
 
   asm volatile(
       "movdqa      %4,%%xmm2                     \n"
@@ -127,7 +131,7 @@
       "sub         %0,%1                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqa      (%0),%%xmm4                   \n"
       "movdqa      0x10(%0), %%xmm5              \n"
       "pxor        (%0,%1), %%xmm4               \n"
@@ -166,7 +170,7 @@
         "=r"(diff)         // %3
       : "m"(kNibbleMask),  // %4
         "m"(kBitCount)     // %5
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+      : "cc", "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
         "xmm7");
 
   return diff;
@@ -176,7 +180,7 @@
 uint32_t HammingDistance_AVX2(const uint8_t* src_a,
                               const uint8_t* src_b,
                               int count) {
-  uint32_t diff = 0u;
+  uint32_t diff;
 
   asm volatile(
       "vbroadcastf128 %4,%%ymm2                  \n"
@@ -186,7 +190,7 @@
       "sub         %0,%1                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqa     (%0),%%ymm4                   \n"
       "vmovdqa     0x20(%0), %%ymm5              \n"
       "vpxor       (%0,%1), %%ymm4, %%ymm4       \n"
@@ -214,15 +218,15 @@
       "vpaddd      %%ymm1,%%ymm0,%%ymm0          \n"
       "vpermq      $0xaa,%%ymm0,%%ymm1           \n"
       "vpaddd      %%ymm1,%%ymm0,%%ymm0          \n"
-      "vmovd       %%xmm0, %3                    \n"
-      "vzeroupper                                \n"
+      "vmovd       %%xmm0,%3                     \n"
+      "vzeroupper  \n"
       : "+r"(src_a),       // %0
         "+r"(src_b),       // %1
         "+r"(count),       // %2
         "=r"(diff)         // %3
       : "m"(kNibbleMask),  // %4
         "m"(kBitCount)     // %5
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+      : "cc", "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
 
   return diff;
 }
@@ -237,7 +241,7 @@
       "pxor        %%xmm5,%%xmm5                 \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm1                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqu      (%1),%%xmm2                   \n"
@@ -261,13 +265,12 @@
       "pshufd      $0x1,%%xmm0,%%xmm1            \n"
       "paddd       %%xmm1,%%xmm0                 \n"
       "movd        %%xmm0,%3                     \n"
-
       : "+r"(src_a),  // %0
         "+r"(src_b),  // %1
         "+r"(count),  // %2
-        "=g"(sse)     // %3
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
+        "=r"(sse)     // %3
+      :
+      : "cc", "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
   return sse;
 }
 
@@ -305,7 +308,7 @@
       "movdqa      %4,%%xmm6                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm1                   \n"
       "lea         0x10(%0),%0                   \n"
       "pmulld      %%xmm6,%%xmm0                 \n"
@@ -341,13 +344,13 @@
       : "+r"(src),        // %0
         "+r"(count),      // %1
         "+rm"(seed),      // %2
-        "=g"(hash)        // %3
+        "=r"(hash)        // %3
       : "m"(kHash16x33),  // %4
         "m"(kHashMul0),   // %5
         "m"(kHashMul1),   // %6
         "m"(kHashMul2),   // %7
         "m"(kHashMul3)    // %8
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+      : "cc", "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
         "xmm7");
   return hash;
 }
diff --git a/source/compare_neon.cc b/source/compare_neon.cc
index afdd601..ee1f7b2 100644
--- a/source/compare_neon.cc
+++ b/source/compare_neon.cc
@@ -31,7 +31,7 @@
   asm volatile(
       "vmov.u16    q4, #0                        \n"  // accumulator
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0, q1}, [%0]!               \n"
       "vld1.8      {q2, q3}, [%1]!               \n"
       "veor.32     q0, q0, q2                    \n"
@@ -64,7 +64,7 @@
       "vmov.u8     q9, #0                        \n"
       "vmov.u8     q11, #0                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"
       "vld1.8      {q1}, [%1]!                   \n"
       "subs        %2, %2, #16                   \n"
diff --git a/source/compare_neon64.cc b/source/compare_neon64.cc
index 70fb9b9..36c5e57 100644
--- a/source/compare_neon64.cc
+++ b/source/compare_neon64.cc
@@ -29,7 +29,7 @@
   asm volatile(
       "movi        v4.8h, #0                     \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b, v1.16b}, [%0], #32   \n"
       "ld1         {v2.16b, v3.16b}, [%1], #32   \n"
       "eor         v0.16b, v0.16b, v2.16b        \n"
@@ -47,7 +47,7 @@
       "fmov        %w3, s4                       \n"
       : "+r"(src_a), "+r"(src_b), "+r"(count), "=r"(diff)
       :
-      : "cc", "v0", "v1", "v2", "v3", "v4");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4");
   return diff;
 }
 
@@ -56,12 +56,12 @@
                              int count) {
   uint32_t sse;
   asm volatile(
-      "eor         v16.16b, v16.16b, v16.16b     \n"
-      "eor         v18.16b, v18.16b, v18.16b     \n"
-      "eor         v17.16b, v17.16b, v17.16b     \n"
-      "eor         v19.16b, v19.16b, v19.16b     \n"
+      "movi        v16.16b, #0                   \n"
+      "movi        v17.16b, #0                   \n"
+      "movi        v18.16b, #0                   \n"
+      "movi        v19.16b, #0                   \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"
       "ld1         {v1.16b}, [%1], #16           \n"
       "subs        %w2, %w2, #16                 \n"
@@ -82,7 +82,136 @@
       "fmov        %w3, s0                       \n"
       : "+r"(src_a), "+r"(src_b), "+r"(count), "=r"(sse)
       :
-      : "cc", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19");
+  return sse;
+}
+
+static const uvec32 kDjb2Multiplicands[] = {
+    {0x0c3525e1,   // 33^15
+     0xa3476dc1,   // 33^14
+     0x3b4039a1,   // 33^13
+     0x4f5f0981},  // 33^12
+    {0x30f35d61,   // 33^11
+     0x855cb541,   // 33^10
+     0x040a9121,   // 33^9
+     0x747c7101},  // 33^8
+    {0xec41d4e1,   // 33^7
+     0x4cfa3cc1,   // 33^6
+     0x025528a1,   // 33^5
+     0x00121881},  // 33^4
+    {0x00008c61,   // 33^3
+     0x00000441,   // 33^2
+     0x00000021,   // 33^1
+     0x00000001},  // 33^0
+};
+
+static const uvec32 kDjb2WidenIndices[] = {
+    {0xffffff00U, 0xffffff01U, 0xffffff02U, 0xffffff03U},
+    {0xffffff04U, 0xffffff05U, 0xffffff06U, 0xffffff07U},
+    {0xffffff08U, 0xffffff09U, 0xffffff0aU, 0xffffff0bU},
+    {0xffffff0cU, 0xffffff0dU, 0xffffff0eU, 0xffffff0fU},
+};
+
+uint32_t HashDjb2_NEON(const uint8_t* src, int count, uint32_t seed) {
+  uint32_t hash = seed;
+  const uint32_t c16 = 0x92d9e201;  // 33^16
+  uint32_t tmp, tmp2;
+  asm("ld1         {v16.4s, v17.4s, v18.4s, v19.4s}, [%[kIdx]] \n"
+      "ld1         {v4.4s, v5.4s, v6.4s, v7.4s}, [%[kMuls]] \n"
+
+      // count is always a multiple of 16.
+      // maintain two accumulators, reduce and then final sum in scalar since
+      // this has better performance on little cores.
+      "1:          \n"
+      "ldr         q0, [%[src]], #16             \n"
+      "subs        %w[count], %w[count], #16     \n"
+      "tbl         v3.16b, {v0.16b}, v19.16b     \n"
+      "tbl         v2.16b, {v0.16b}, v18.16b     \n"
+      "tbl         v1.16b, {v0.16b}, v17.16b     \n"
+      "tbl         v0.16b, {v0.16b}, v16.16b     \n"
+      "mul         v3.4s, v3.4s, v7.4s           \n"
+      "mul         v2.4s, v2.4s, v6.4s           \n"
+      "mla         v3.4s, v1.4s, v5.4s           \n"
+      "mla         v2.4s, v0.4s, v4.4s           \n"
+      "addv        s1, v3.4s                     \n"
+      "addv        s0, v2.4s                     \n"
+      "fmov        %w[tmp2], s1                  \n"
+      "fmov        %w[tmp], s0                   \n"
+      "add         %w[tmp], %w[tmp], %w[tmp2]    \n"
+      "madd        %w[hash], %w[hash], %w[c16], %w[tmp] \n"
+      "b.gt        1b                            \n"
+      : [hash] "+r"(hash),                // %[hash]
+        [count] "+r"(count),              // %[count]
+        [tmp] "=&r"(tmp),                 // %[tmp]
+        [tmp2] "=&r"(tmp2)                // %[tmp2]
+      : [src] "r"(src),                   // %[src]
+        [kMuls] "r"(kDjb2Multiplicands),  // %[kMuls]
+        [kIdx] "r"(kDjb2WidenIndices),    // %[kIdx]
+        [c16] "r"(c16)                    // %[c16]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
+        "v17", "v18", "v19");
+  return hash;
+}
+
+uint32_t HammingDistance_NEON_DotProd(const uint8_t* src_a,
+                                      const uint8_t* src_b,
+                                      int count) {
+  uint32_t diff;
+  asm volatile(
+      "movi        v4.4s, #0                     \n"
+      "movi        v5.4s, #0                     \n"
+      "movi        v6.16b, #1                    \n"
+
+      "1:          \n"
+      "ldp         q0, q1, [%0], #32             \n"
+      "ldp         q2, q3, [%1], #32             \n"
+      "eor         v0.16b, v0.16b, v2.16b        \n"
+      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
+      "eor         v1.16b, v1.16b, v3.16b        \n"
+      "cnt         v0.16b, v0.16b                \n"
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "cnt         v1.16b, v1.16b                \n"
+      "subs        %w2, %w2, #32                 \n"
+      "udot        v4.4s, v0.16b, v6.16b         \n"
+      "udot        v5.4s, v1.16b, v6.16b         \n"
+      "b.gt        1b                            \n"
+
+      "add         v0.4s, v4.4s, v5.4s           \n"
+      "addv        s0, v0.4s                     \n"
+      "fmov        %w3, s0                       \n"
+      : "+r"(src_a), "+r"(src_b), "+r"(count), "=r"(diff)
+      :
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6");
+  return diff;
+}
+
+uint32_t SumSquareError_NEON_DotProd(const uint8_t* src_a,
+                                     const uint8_t* src_b,
+                                     int count) {
+  // count is guaranteed to be a multiple of 32.
+  uint32_t sse;
+  asm volatile(
+      "movi        v4.4s, #0                     \n"
+      "movi        v5.4s, #0                     \n"
+
+      "1:          \n"
+      "ldp         q0, q2, [%0], #32             \n"
+      "ldp         q1, q3, [%1], #32             \n"
+      "subs        %w2, %w2, #32                 \n"
+      "uabd        v0.16b, v0.16b, v1.16b        \n"
+      "uabd        v1.16b, v2.16b, v3.16b        \n"
+      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
+      "udot        v4.4s, v0.16b, v0.16b         \n"
+      "udot        v5.4s, v1.16b, v1.16b         \n"
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "b.gt        1b                            \n"
+
+      "add         v0.4s, v4.4s, v5.4s           \n"
+      "addv        s0, v0.4s                     \n"
+      "fmov        %w3, s0                       \n"
+      : "+r"(src_a), "+r"(src_b), "+r"(count), "=r"(sse)
+      :
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5");
   return sse;
 }
 
diff --git a/source/compare_win.cc b/source/compare_win.cc
index 9bb27f1..9d5bb27 100644
--- a/source/compare_win.cc
+++ b/source/compare_win.cc
@@ -23,8 +23,8 @@
 #endif
 
 // This module is for 32 bit Visual C x86
-#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && \
-    !defined(__clang__) && defined(_M_IX86)
+#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && defined(_M_IX86) && \
+    (!defined(__clang__) || defined(LIBYUV_ENABLE_ROWWIN))
 
 uint32_t HammingDistance_SSE42(const uint8_t* src_a,
                                const uint8_t* src_b,
diff --git a/source/convert.cc b/source/convert.cc
index 6ac5bc4..7ebdad2 100644
--- a/source/convert.cc
+++ b/source/convert.cc
@@ -33,7 +33,7 @@
   return v >= 0 ? v : -v;
 }
 
-// Any I4xx To I420 format with mirroring.
+// Any I4xx To I420 format
 static int I4xxToI420(const uint8_t* src_y,
                       int src_stride_y,
                       const uint8_t* src_u,
@@ -50,20 +50,19 @@
                       int src_y_height,
                       int src_uv_width,
                       int src_uv_height) {
-  const int dst_y_width = Abs(src_y_width);
+  const int dst_y_width = src_y_width;
   const int dst_y_height = Abs(src_y_height);
   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
   int r;
-  if (src_uv_width <= 0 || src_uv_height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v ||
+      src_y_width <= 0 || src_y_height == 0 || src_uv_width <= 0 ||
+      src_uv_height == 0) {
     return -1;
   }
   if (dst_y) {
-    r = ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
-                   dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_y_width,
+              src_y_height);
   }
   r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
                  dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
@@ -75,9 +74,7 @@
   return r;
 }
 
-// Copy I420 with optional flipping.
-// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
-// is does row coalescing.
+// Copy I420 with optional vertical flipping using negative height.
 LIBYUV_API
 int I420Copy(const uint8_t* src_y,
              int src_stride_y,
@@ -200,8 +197,10 @@
   }
 
   // Convert Y plane.
-  Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
-                    height);
+  if (dst_y) {
+    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
+                      height);
+  }
   // Convert UV planes.
   Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
                     uv_height);
@@ -510,7 +509,7 @@
                     dst_v, dst_stride_v, width, height, 12);
 }
 
-// Any Ix10 To I010 format with mirroring.
+// Any Ix10 To I010 format
 static int Ix10ToI010(const uint16_t* src_y,
                       int src_stride_y,
                       const uint16_t* src_u,
@@ -527,22 +526,19 @@
                       int height,
                       int subsample_x,
                       int subsample_y) {
-  const int dst_y_width = Abs(width);
+  const int dst_y_width = width;
   const int dst_y_height = Abs(height);
   const int src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
   const int src_uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
   int r;
-  if (width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
   if (dst_y) {
-    r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                      dst_y_width, dst_y_height, kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = ScalePlane_12(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
                     dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
@@ -594,7 +590,7 @@
                     dst_v, dst_stride_v, width, height, 1, 0);
 }
 
-// Any I[420]1[02] to P[420]1[02] format with mirroring.
+// Any I[420]1[02] to P[420]1[02] format
 static int IxxxToPxxx(const uint16_t* src_y,
                       int src_stride_y,
                       const uint16_t* src_u,
@@ -642,6 +638,165 @@
 }
 
 LIBYUV_API
+int I010ToNV12(const uint16_t* src_y,
+               int src_stride_y,
+               const uint16_t* src_u,
+               int src_stride_u,
+               const uint16_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_uv,
+               int dst_stride_uv,
+               int width,
+               int height) {
+  int y;
+  int halfwidth = (width + 1) >> 1;
+  int halfheight = (height + 1) >> 1;
+  const int scale = 16385;  // 16384 for 10 bits
+  void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
+                          int width) = Convert16To8Row_C;
+  void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
+                     uint8_t* dst_uv, int width) = MergeUVRow_C;
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
+      height == 0) {
+    return -1;
+  }
+  // Negative height means invert the image.
+  if (height < 0) {
+    height = -height;
+    halfheight = (height + 1) >> 1;
+    src_y = src_y + (height - 1) * src_stride_y;
+    src_u = src_u + (halfheight - 1) * src_stride_u;
+    src_v = src_v + (halfheight - 1) * src_stride_v;
+    src_stride_y = -src_stride_y;
+    src_stride_u = -src_stride_u;
+    src_stride_v = -src_stride_v;
+  }
+#if defined(HAS_CONVERT16TO8ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    Convert16To8Row = Convert16To8Row_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      Convert16To8Row = Convert16To8Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_CONVERT16TO8ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    Convert16To8Row = Convert16To8Row_SME;
+  }
+#endif
+#if defined(HAS_CONVERT16TO8ROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    Convert16To8Row = Convert16To8Row_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      Convert16To8Row = Convert16To8Row_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_CONVERT16TO8ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    Convert16To8Row = Convert16To8Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      Convert16To8Row = Convert16To8Row_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
+    if (IS_ALIGNED(width, 64)) {
+      Convert16To8Row = Convert16To8Row_AVX512BW;
+    }
+  }
+#endif
+
+#if defined(HAS_MERGEUVROW_SSE2)
+  if (TestCpuFlag(kCpuHasSSE2)) {
+    MergeUVRow = MergeUVRow_Any_SSE2;
+    if (IS_ALIGNED(halfwidth, 16)) {
+      MergeUVRow = MergeUVRow_SSE2;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    MergeUVRow = MergeUVRow_Any_AVX2;
+    if (IS_ALIGNED(halfwidth, 16)) {
+      MergeUVRow = MergeUVRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    MergeUVRow = MergeUVRow_Any_AVX512BW;
+    if (IS_ALIGNED(halfwidth, 32)) {
+      MergeUVRow = MergeUVRow_AVX512BW;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    MergeUVRow = MergeUVRow_Any_NEON;
+    if (IS_ALIGNED(halfwidth, 16)) {
+      MergeUVRow = MergeUVRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow = MergeUVRow_SME;
+  }
+#endif
+#if defined(HAS_MERGEUVROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    MergeUVRow = MergeUVRow_Any_MSA;
+    if (IS_ALIGNED(halfwidth, 16)) {
+      MergeUVRow = MergeUVRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    MergeUVRow = MergeUVRow_Any_LSX;
+    if (IS_ALIGNED(halfwidth, 16)) {
+      MergeUVRow = MergeUVRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_MERGEUVROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    MergeUVRow = MergeUVRow_RVV;
+  }
+#endif
+
+  // Convert Y plane.
+  if (dst_y) {
+    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
+                      height);
+  }
+
+  {
+    // Allocate a row of uv.
+    align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
+    uint8_t* row_v = row_u + ((halfwidth + 31) & ~31);
+    if (!row_u)
+      return 1;
+
+    for (y = 0; y < halfheight; ++y) {
+      Convert16To8Row(src_u, row_u, scale, halfwidth);
+      Convert16To8Row(src_v, row_v, scale, halfwidth);
+      MergeUVRow(row_u, row_v, dst_uv, halfwidth);
+      src_u += src_stride_u;
+      src_v += src_stride_v;
+      dst_uv += dst_stride_uv;
+    }
+    free_aligned_buffer_64(row_u);
+  }
+  return 0;
+}
+
+LIBYUV_API
 int I210ToP210(const uint16_t* src_y,
                int src_stride_y,
                const uint16_t* src_u,
@@ -989,7 +1144,8 @@
                          int source_y_fraction) = InterpolateRow_C;
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
-  if (!src_u || !src_v || !dst_vu || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_vu || width <= 0 ||
+      height == 0) {
     return -1;
   }
   // Negative height means invert the image.
@@ -1035,6 +1191,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow = MergeUVRow_Any_MSA;
@@ -1080,6 +1241,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -1166,7 +1332,8 @@
                int dst_stride_uv,
                int width,
                int height) {
-  if (!src_y || !src_u || !src_v || !dst_uv || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
+      height == 0) {
     return -1;
   }
   // Negative height means invert the image.
@@ -1219,7 +1386,7 @@
                int height) {
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
-  if (!dst_u || !dst_v || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !dst_u || !dst_v || width <= 0 || height == 0) {
     return -1;
   }
   // Negative height means invert the image.
@@ -1249,7 +1416,7 @@
                int height) {
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
-  if (!dst_vu || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !dst_vu || width <= 0 || height == 0) {
     return -1;
   }
   // Negative height means invert the image.
@@ -1283,7 +1450,8 @@
                int height) {
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
-  if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
   // Negative height means invert the image.
@@ -1351,16 +1519,12 @@
                int width,
                int height) {
   int r;
-  if (width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                   Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
               SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
@@ -1380,23 +1544,19 @@
                int width,
                int height) {
   int r;
-  if (width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                   Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
               dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
   return r;
 }
 
-// Any P[420]1[02] to I[420]1[02] format with mirroring.
+// Any P[420]1[02] to I[420]1[02] format
 static int PxxxToIxxx(const uint16_t* src_y,
                       int src_stride_y,
                       const uint16_t* src_uv,
@@ -1414,7 +1574,8 @@
                       int depth) {
   const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
   const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
-  if (width <= 0 || height == 0) {
+  if (!src_y || !dst_y || !src_uv || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
   ConvertToLSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
@@ -1472,16 +1633,12 @@
                int width,
                int height) {
   int r;
-  if (width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane_16(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                      Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
                  SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
@@ -1501,16 +1658,12 @@
                int width,
                int height) {
   int r;
-  if (width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane_16(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                      Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
                  dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
@@ -1782,6 +1935,14 @@
     }
   }
 #endif
+#if defined(HAS_AYUVTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    AYUVToUVRow = AYUVToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      AYUVToUVRow = AYUVToUVRow_SVE2;
+    }
+  }
+#endif
 
   for (y = 0; y < height - 1; y += 2) {
     AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
@@ -1851,6 +2012,14 @@
     }
   }
 #endif
+#if defined(HAS_AYUVTOVUROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    AYUVToVURow = AYUVToVURow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      AYUVToVURow = AYUVToVURow_SVE2;
+    }
+  }
+#endif
 
   for (y = 0; y < height - 1; y += 2) {
     AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
@@ -1902,6 +2071,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -1910,6 +2087,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYRow = ARGBToYRow_Any_SSSE3;
@@ -2064,6 +2249,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -2072,6 +2265,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYRow = ARGBToYRow_Any_SSSE3;
@@ -2227,6 +2428,14 @@
     }
   }
 #endif
+#if defined(HAS_BGRATOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    BGRAToYRow = BGRAToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      BGRAToYRow = BGRAToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_BGRATOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     BGRAToUVRow = BGRAToUVRow_Any_NEON;
@@ -2235,6 +2444,14 @@
     }
   }
 #endif
+#if defined(HAS_BGRATOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    BGRAToUVRow = BGRAToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      BGRAToUVRow = BGRAToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_BGRATOYROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     BGRAToYRow = BGRAToYRow_Any_SSSE3;
@@ -2386,6 +2603,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYRow = ABGRToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYRow = ABGRToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ABGRToUVRow = ABGRToUVRow_Any_NEON;
@@ -2394,6 +2619,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ABGRToUVRow = ABGRToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ABGRToUVRow = ABGRToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYRow = ABGRToYRow_Any_MSA;
@@ -2495,6 +2728,14 @@
     }
   }
 #endif
+#if defined(HAS_RGBATOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    RGBAToYRow = RGBAToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      RGBAToYRow = RGBAToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_RGBATOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     RGBAToUVRow = RGBAToUVRow_Any_NEON;
@@ -2503,6 +2744,14 @@
     }
   }
 #endif
+#if defined(HAS_RGBATOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RGBAToUVRow = RGBAToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      RGBAToUVRow = RGBAToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_RGBATOYROW_MSA) && defined(HAS_RGBATOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RGBAToYRow = RGBAToYRow_Any_MSA;
@@ -3016,6 +3265,14 @@
     }
   }
 #endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYRow = ARGBToYRow_Any_SSSE3;
@@ -3161,19 +3418,23 @@
     }
   }
 #endif
-#if defined(HAS_RAWTOYJROW_LSX)
+#if defined(HAS_RAWTOYJROW_LSX) && defined(HAS_RAWTOUVJROW_LSX)
   if (TestCpuFlag(kCpuHasLSX)) {
+    RAWToUVJRow = RAWToUVJRow_Any_LSX;
     RAWToYJRow = RAWToYJRow_Any_LSX;
     if (IS_ALIGNED(width, 16)) {
       RAWToYJRow = RAWToYJRow_LSX;
+      RAWToUVJRow = RAWToUVJRow_LSX;
     }
   }
 #endif
-#if defined(HAS_RAWTOYJROW_LASX)
+#if defined(HAS_RAWTOYJROW_LASX) && defined(HAS_RAWTOUVJROW_LASX)
   if (TestCpuFlag(kCpuHasLASX)) {
+    RAWToUVJRow = RAWToUVJRow_Any_LASX;
     RAWToYJRow = RAWToYJRow_Any_LASX;
     if (IS_ALIGNED(width, 32)) {
       RAWToYJRow = RAWToYJRow_LASX;
+      RAWToUVJRow = RAWToUVJRow_LASX;
     }
   }
 #endif
@@ -3194,6 +3455,14 @@
     }
   }
 #endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYJROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
@@ -3272,6 +3541,461 @@
 }
 #undef HAS_RAWTOYJROW
 
+// RAW big endian (rgb in memory) to I444
+// 2 step conversion of RAWToARGB then ARGBToY and ARGBToUV444
+LIBYUV_API
+int RAWToI444(const uint8_t* src_raw,
+              int src_stride_raw,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_u,
+              int dst_stride_u,
+              uint8_t* dst_v,
+              int dst_stride_v,
+              int width,
+              int height) {
+  int y;
+  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
+      RAWToARGBRow_C;
+  void (*ARGBToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
+      ARGBToYRow_C;
+  void (*ARGBToUV444Row)(const uint8_t* src_raw, uint8_t* dst_u, uint8_t* dst_v,
+                         int width) = ARGBToUV444Row_C;
+  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
+    return -1;
+  }
+  if (height < 0) {
+    height = -height;
+    src_raw = src_raw + (height - 1) * src_stride_raw;
+    src_stride_raw = -src_stride_raw;
+  }
+  // TODO: add row coalesce when main loop handles large width in blocks
+  // TODO: implement UV444 or trim the ifdef below
+#if defined(HAS_ARGBTOUV444ROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUV444Row = ARGBToUV444Row_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUV444Row = ARGBToUV444Row_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUV444Row = ARGBToUV444Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_NEON_I8MM)
+  if (TestCpuFlag(kCpuHasNeonI8MM)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_NEON_I8MM;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUV444Row = ARGBToUV444Row_NEON_I8MM;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUV444Row = ARGBToUV444Row_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUV444Row = ARGBToUV444Row_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUV444ROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUV444Row = ARGBToUV444Row_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToYRow = ARGBToYRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToYRow = ARGBToYRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYRow = ARGBToYRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToYRow = ARGBToYRow_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToYRow = ARGBToYRow_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToYRow = ARGBToYRow_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYRow = ARGBToYRow_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    ARGBToYRow = ARGBToYRow_RVV;
+  }
+#endif
+
+#if defined(HAS_RAWTOARGBROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    RAWToARGBRow = RAWToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      RAWToARGBRow = RAWToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RAWToARGBRow = RAWToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    RAWToARGBRow = RAWToARGBRow_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    RAWToARGBRow = RAWToARGBRow_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    RAWToARGBRow = RAWToARGBRow_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_LASX;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    RAWToARGBRow = RAWToARGBRow_RVV;
+  }
+#endif
+
+  {
+    // Allocate a row of ARGB.
+    const int row_size = width * 4;
+    align_buffer_64(row, row_size);
+    if (!row)
+      return 1;
+
+    for (y = 0; y < height; ++y) {
+      RAWToARGBRow(src_raw, row, width);
+      ARGBToUV444Row(row, dst_u, dst_v, width);
+      ARGBToYRow(row, dst_y, width);
+      src_raw += src_stride_raw;
+      dst_y += dst_stride_y;
+      dst_u += dst_stride_u;
+      dst_v += dst_stride_v;
+    }
+    free_aligned_buffer_64(row);
+  }
+  return 0;
+}
+
+// RAW big endian (rgb in memory) to J444
+// 2 step conversion of RAWToARGB then ARGBToYJ and ARGBToUVJ444
+LIBYUV_API
+int RAWToJ444(const uint8_t* src_raw,
+              int src_stride_raw,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_u,
+              int dst_stride_u,
+              uint8_t* dst_v,
+              int dst_stride_v,
+              int width,
+              int height) {
+  int y;
+  void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
+      RAWToARGBRow_C;
+  void (*ARGBToYJRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
+      ARGBToYJRow_C;
+  void (*ARGBToUVJ444Row)(const uint8_t* src_raw, uint8_t* dst_u,
+                          uint8_t* dst_v, int width) = ARGBToUVJ444Row_C;
+  if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
+    return -1;
+  }
+  if (height < 0) {
+    height = -height;
+    src_raw = src_raw + (height - 1) * src_stride_raw;
+    src_stride_raw = -src_stride_raw;
+  }
+  // TODO: add row coalesce when main loop handles large width in blocks
+#if defined(HAS_ARGBTOUVJ444ROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_NEON_I8MM)
+  if (TestCpuFlag(kCpuHasNeonI8MM)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON_I8MM;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON_I8MM;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToYJRow = ARGBToYJRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYJRow = ARGBToYJRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToYJRow = ARGBToYJRow_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToYJRow = ARGBToYJRow_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToYJRow = ARGBToYJRow_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYJRow = ARGBToYJRow_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    ARGBToYJRow = ARGBToYJRow_RVV;
+  }
+#endif
+
+#if defined(HAS_RAWTOARGBROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    RAWToARGBRow = RAWToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      RAWToARGBRow = RAWToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RAWToARGBRow = RAWToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    RAWToARGBRow = RAWToARGBRow_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    RAWToARGBRow = RAWToARGBRow_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      RAWToARGBRow = RAWToARGBRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    RAWToARGBRow = RAWToARGBRow_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_LASX;
+    }
+  }
+#endif
+#if defined(HAS_RAWTOARGBROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    RAWToARGBRow = RAWToARGBRow_RVV;
+  }
+#endif
+
+  {
+    // Allocate a row of ARGB.
+    const int row_size = width * 4;
+    align_buffer_64(row, row_size);
+    if (!row)
+      return 1;
+
+    for (y = 0; y < height; ++y) {
+      RAWToARGBRow(src_raw, row, width);
+      ARGBToUVJ444Row(row, dst_u, dst_v, width);
+      ARGBToYJRow(row, dst_y, width);
+      src_raw += src_stride_raw;
+      dst_y += dst_stride_y;
+      dst_u += dst_stride_u;
+      dst_v += dst_stride_v;
+    }
+    free_aligned_buffer_64(row);
+  }
+  return 0;
+}
+
 // Convert RGB565 to I420.
 LIBYUV_API
 int RGB565ToI420(const uint8_t* src_rgb565,
@@ -3314,18 +4038,22 @@
 // Neon version does direct RGB565 to YUV.
 #if defined(HAS_RGB565TOYROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
-    RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
     RGB565ToYRow = RGB565ToYRow_Any_NEON;
-    if (IS_ALIGNED(width, 8)) {
+    if (IS_ALIGNED(width, 16)) {
       RGB565ToYRow = RGB565ToYRow_NEON;
-      if (IS_ALIGNED(width, 16)) {
-        RGB565ToUVRow = RGB565ToUVRow_NEON;
-      }
     }
   }
+#endif
+// Neon version does direct RGB565 to YUV.
+#if defined(HAS_RGB565TOUVROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      RGB565ToUVRow = RGB565ToUVRow_NEON;
+    }
+  }
+#endif
 // MSA version does direct RGB565 to YUV.
-#elif (defined(HAS_RGB565TOYROW_MSA) || defined(HAS_RGB565TOYROW_LSX) || \
-       defined(HAS_RGB565TOYROW_LASX))
 #if defined(HAS_RGB565TOYROW_MSA) && defined(HAS_RGB565TOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
@@ -3357,7 +4085,6 @@
   }
 #endif
 // Other platforms do intermediate conversion from RGB565 to ARGB.
-#else
 #if defined(HAS_RGB565TOARGBROW_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
@@ -3382,14 +4109,6 @@
     }
   }
 #endif
-#if defined(HAS_ARGBTOUVROW_SSSE3)
-  if (TestCpuFlag(kCpuHasSSSE3)) {
-    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
-    if (IS_ALIGNED(width, 16)) {
-      ARGBToUVRow = ARGBToUVRow_SSSE3;
-    }
-  }
-#endif
 #if defined(HAS_ARGBTOYROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     ARGBToYRow = ARGBToYRow_Any_AVX2;
@@ -3398,6 +4117,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVRow = ARGBToUVRow_SSSE3;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
@@ -3406,7 +4133,6 @@
     }
   }
 #endif
-#endif
   {
 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
       defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
@@ -3496,18 +4222,22 @@
 // Neon version does direct ARGB1555 to YUV.
 #if defined(HAS_ARGB1555TOYROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
-    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
     if (IS_ALIGNED(width, 8)) {
       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
-      if (IS_ALIGNED(width, 16)) {
-        ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
-      }
     }
   }
+#endif
+#if defined(HAS_ARGB1555TOUVROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
+    }
+  }
+#endif
+
 // MSA version does direct ARGB1555 to YUV.
-#elif (defined(HAS_ARGB1555TOYROW_MSA) || defined(HAS_ARGB1555TOYROW_LSX) || \
-       defined(HAS_ARGB1555TOYROW_LASX))
 #if defined(HAS_ARGB1555TOYROW_MSA) && defined(HAS_ARGB1555TOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
@@ -3538,8 +4268,8 @@
     }
   }
 #endif
+
 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
-#else
 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
@@ -3588,7 +4318,6 @@
     }
   }
 #endif
-#endif
   {
 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
       defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
@@ -3680,17 +4409,20 @@
 // Neon version does direct ARGB4444 to YUV.
 #if defined(HAS_ARGB4444TOYROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
-    ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
     if (IS_ALIGNED(width, 8)) {
       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
-      if (IS_ALIGNED(width, 16)) {
-        ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
-      }
     }
   }
-// Other platforms do intermediate conversion from ARGB4444 to ARGB.
-#else
+#endif
+#if defined(HAS_ARGB4444TOUVROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
+    }
+  }
+#endif
 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
@@ -3803,7 +4535,6 @@
     }
   }
 #endif
-#endif
 
   {
 #if !(defined(HAS_ARGB4444TOYROW_NEON))
@@ -4049,6 +4780,138 @@
                                 dst_stride_v, width, height, kRotate0);
 }
 
+// depth is source bits measured from lsb; For msb use 16
+static int Biplanar16bitTo8bit(const uint16_t* src_y,
+                               int src_stride_y,
+                               const uint16_t* src_uv,
+                               int src_stride_uv,
+                               uint8_t* dst_y,
+                               int dst_stride_y,
+                               uint8_t* dst_uv,
+                               int dst_stride_uv,
+                               int width,
+                               int height,
+                               int subsample_x,
+                               int subsample_y,
+                               int depth) {
+  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
+  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
+  int scale = 1 << (24 - depth);
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
+    return -1;
+  }
+  // Negative height means invert the image.
+  if (height < 0) {
+    height = -height;
+    uv_height = -uv_height;
+    src_y = src_y + (height - 1) * src_stride_y;
+    src_uv = src_uv + (uv_height - 1) * src_stride_uv;
+    src_stride_y = -src_stride_y;
+    src_stride_uv = -src_stride_uv;
+  }
+
+  // Convert Y plane.
+  if (dst_y) {
+    Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
+                      height);
+  }
+  // Convert UV planes.
+  Convert16To8Plane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, scale,
+                    uv_width * 2, uv_height);
+  return 0;
+}
+
+// Convert 10 bit P010 to 8 bit NV12.
+// Depth set to 16 because P010 uses 10 msb and this function keeps the upper 8
+// bits of the specified number of bits.
+LIBYUV_API
+int P010ToNV12(const uint16_t* src_y,
+               int src_stride_y,
+               const uint16_t* src_uv,
+               int src_stride_uv,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_uv,
+               int dst_stride_uv,
+               int width,
+               int height) {
+  return Biplanar16bitTo8bit(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
+                             dst_stride_y, dst_uv, dst_stride_uv, width, height,
+                             1, 1, 16);
+}
+
+static int Planar8bitTo8bit(const uint8_t* src_y,
+                            int src_stride_y,
+                            const uint8_t* src_u,
+                            int src_stride_u,
+                            const uint8_t* src_v,
+                            int src_stride_v,
+                            uint8_t* dst_y,
+                            int dst_stride_y,
+                            uint8_t* dst_u,
+                            int dst_stride_u,
+                            uint8_t* dst_v,
+                            int dst_stride_v,
+                            int width,
+                            int height,
+                            int subsample_x,
+                            int subsample_y,
+                            int scale_y,
+                            int bias_y,
+                            int scale_uv,
+                            int bias_uv) {
+  int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
+  int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
+    return -1;
+  }
+  // Negative height means invert the image.
+  if (height < 0) {
+    height = -height;
+    uv_height = -uv_height;
+    src_y = src_y + (height - 1) * src_stride_y;
+    src_u = src_u + (uv_height - 1) * src_stride_u;
+    src_v = src_v + (uv_height - 1) * src_stride_v;
+    src_stride_y = -src_stride_y;
+    src_stride_u = -src_stride_u;
+    src_stride_v = -src_stride_v;
+  }
+
+  // Convert Y plane.
+  if (dst_y) {
+    Convert8To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale_y, bias_y,
+                     width, height);
+  }
+  // Convert UV planes.
+  Convert8To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale_uv, bias_uv,
+                   uv_width, uv_height);
+  Convert8To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale_uv, bias_uv,
+                   uv_width, uv_height);
+  return 0;
+}
+
+LIBYUV_API
+int J420ToI420(const uint8_t* src_y,
+               int src_stride_y,
+               const uint8_t* src_u,
+               int src_stride_u,
+               const uint8_t* src_v,
+               int src_stride_v,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_u,
+               int dst_stride_u,
+               uint8_t* dst_v,
+               int dst_stride_v,
+               int width,
+               int height) {
+  return Planar8bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
+                          src_stride_v, dst_y, dst_stride_y, dst_u,
+                          dst_stride_u, dst_v, dst_stride_v, width, height, 1,
+                          1, 220, 16, 225, 16);
+}
+
 #ifdef __cplusplus
 }  // extern "C"
 }  // namespace libyuv
diff --git a/source/convert_argb.cc b/source/convert_argb.cc
index 871fea5..41997fe 100644
--- a/source/convert_argb.cc
+++ b/source/convert_argb.cc
@@ -14,9 +14,6 @@
 
 #include "libyuv/convert_from_argb.h"
 #include "libyuv/cpu_id.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
 #include "libyuv/planar_functions.h"  // For CopyPlane and ARGBShuffle.
 #include "libyuv/rotate_argb.h"
 #include "libyuv/row.h"
@@ -112,6 +109,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGBRow = I422ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGBRow = I422ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGBRow = I422ToARGBRow_Any_MSA;
@@ -366,6 +373,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGBRow = I422ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGBRow = I422ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGBRow = I422ToARGBRow_Any_MSA;
@@ -609,6 +626,16 @@
     }
   }
 #endif
+#if defined(HAS_I444TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444ToARGBRow = I444ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444ToARGBRow = I444ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444ToARGBRow = I444ToARGBRow_Any_MSA;
@@ -942,6 +969,24 @@
     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
     dst_stride_ar30 = -dst_stride_ar30;
   }
+#if defined(HAS_I210TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210ToAR30Row = I210ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210ToAR30Row = I210ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210ToAR30Row = I210ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I210TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210ToAR30Row = I210ToAR30Row_SME;
+  }
+#endif
 #if defined(HAS_I210TOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
@@ -1118,6 +1163,24 @@
     }
   }
 #endif
+#if defined(HAS_I212TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I212ToAR30Row = I212ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I212ToAR30Row = I212ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I212TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I212ToAR30Row = I212ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I212TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I212ToAR30Row = I212ToAR30Row_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     I212ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
     dst_ar30 += dst_stride_ar30;
@@ -1160,6 +1223,24 @@
     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
     dst_stride_ar30 = -dst_stride_ar30;
   }
+#if defined(HAS_I210TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210ToAR30Row = I210ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210ToAR30Row = I210ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210ToAR30Row = I210ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I210TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210ToAR30Row = I210ToAR30Row_SME;
+  }
+#endif
 #if defined(HAS_I210TOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
@@ -1315,6 +1396,24 @@
     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
     dst_stride_ar30 = -dst_stride_ar30;
   }
+#if defined(HAS_I410TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToAR30Row = I410ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToAR30Row = I410ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToAR30Row = I410ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToAR30Row = I410ToAR30Row_SME;
+  }
+#endif
 #if defined(HAS_I410TOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410ToAR30Row = I410ToAR30Row_Any_SSSE3;
@@ -1377,6 +1476,24 @@
     }
   }
 #endif
+#if defined(HAS_I210TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210ToARGBRow = I210ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210ToARGBRow = I210ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210ToARGBRow = I210ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I210TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210ToARGBRow = I210ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I210TOARGBROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
@@ -1549,6 +1666,24 @@
     }
   }
 #endif
+#if defined(HAS_I212TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I212ToARGBRow = I212ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I212ToARGBRow = I212ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I212TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I212ToARGBRow = I212ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I212TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I212ToARGBRow = I212ToARGBRow_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     I212ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
     dst_argb += dst_stride_argb;
@@ -1597,6 +1732,24 @@
     }
   }
 #endif
+#if defined(HAS_I210TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210ToARGBRow = I210ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210ToARGBRow = I210ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210ToARGBRow = I210ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I210TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210ToARGBRow = I210ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I210TOARGBROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
@@ -1758,6 +1911,24 @@
     }
   }
 #endif
+#if defined(HAS_I410TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToARGBRow = I410ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToARGBRow = I410ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToARGBRow = I410ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToARGBRow = I410ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410TOARGBROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     I410ToARGBRow = I410ToARGBRow_Any_AVX2;
@@ -1816,6 +1987,24 @@
     }
   }
 #endif
+#if defined(HAS_P210TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P210ToARGBRow = P210ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P210ToARGBRow = P210ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P210TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P210ToARGBRow = P210ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_P210TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P210ToARGBRow = P210ToARGBRow_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     P210ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
     dst_argb += dst_stride_argb;
@@ -1867,6 +2056,24 @@
     }
   }
 #endif
+#if defined(HAS_P210TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P210ToARGBRow = P210ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P210ToARGBRow = P210ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P210TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P210ToARGBRow = P210ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_P210TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P210ToARGBRow = P210ToARGBRow_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     P210ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
     dst_argb += dst_stride_argb;
@@ -1916,6 +2123,24 @@
     }
   }
 #endif
+#if defined(HAS_P210TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P210ToAR30Row = P210ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P210ToAR30Row = P210ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P210TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P210ToAR30Row = P210ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_P210TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P210ToAR30Row = P210ToAR30Row_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     P210ToAR30Row(src_y, src_uv, dst_ar30, yuvconstants, width);
     dst_ar30 += dst_stride_ar30;
@@ -1967,6 +2192,24 @@
     }
   }
 #endif
+#if defined(HAS_P210TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P210ToAR30Row = P210ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P210ToAR30Row = P210ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P210TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P210ToAR30Row = P210ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_P210TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P210ToAR30Row = P210ToAR30Row_SME;
+  }
+#endif
   for (y = 0; y < height; ++y) {
     P210ToAR30Row(src_y, src_uv, dst_ar30, yuvconstants, width);
     dst_ar30 += dst_stride_ar30;
@@ -2035,6 +2278,16 @@
     }
   }
 #endif
+#if defined(HAS_I422ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422AlphaToARGBRow = I422AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422AlphaToARGBRow = I422AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422ALPHATOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
@@ -2101,6 +2354,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2178,6 +2447,16 @@
     }
   }
 #endif
+#if defined(HAS_I422ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422AlphaToARGBRow = I422AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422AlphaToARGBRow = I422AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422ALPHATOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
@@ -2244,6 +2523,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2319,6 +2614,16 @@
     }
   }
 #endif
+#if defined(HAS_I444ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444ALPHATOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444AlphaToARGBRow = I444AlphaToARGBRow_Any_MSA;
@@ -2369,6 +2674,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I444AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2549,6 +2870,24 @@
     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     dst_stride_argb = -dst_stride_argb;
   }
+#if defined(HAS_I210ALPHATOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210AlphaToARGBRow = I210AlphaToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I210ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I210ALPHATOARGBROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I210AlphaToARGBRow = I210AlphaToARGBRow_Any_SSSE3;
@@ -2602,6 +2941,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I210AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2655,6 +3010,24 @@
     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     dst_stride_argb = -dst_stride_argb;
   }
+#if defined(HAS_I210ALPHATOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I210AlphaToARGBRow = I210AlphaToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I210ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I210ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I210AlphaToARGBRow = I210AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I210ALPHATOARGBROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I210AlphaToARGBRow = I210AlphaToARGBRow_Any_SSSE3;
@@ -2708,6 +3081,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I210AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2759,6 +3148,24 @@
     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     dst_stride_argb = -dst_stride_argb;
   }
+#if defined(HAS_I410ALPHATOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410AlphaToARGBRow = I410AlphaToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410ALPHATOARGBROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410AlphaToARGBRow = I410AlphaToARGBRow_Any_SSSE3;
@@ -2812,6 +3219,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I410AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
@@ -2881,6 +3304,16 @@
     }
   }
 #endif
+#if defined(HAS_I400TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I400ToARGBRow = I400ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I400TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I400ToARGBRow = I400ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I400TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I400ToARGBRow = I400ToARGBRow_Any_MSA;
@@ -3323,6 +3756,11 @@
     }
   }
 #endif
+#if defined(HAS_RGB24TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RGB24ToARGBRow = RGB24ToARGBRow_SVE2;
+  }
+#endif
 #if defined(HAS_RGB24TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
@@ -3395,6 +3833,14 @@
     }
   }
 #endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_RAWTOARGBROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     RAWToARGBRow = RAWToARGBRow_Any_NEON;
@@ -3403,6 +3849,11 @@
     }
   }
 #endif
+#if defined(HAS_RAWTOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RAWToARGBRow = RAWToARGBRow_SVE2;
+  }
+#endif
 #if defined(HAS_RAWTOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RAWToARGBRow = RAWToARGBRow_Any_MSA;
@@ -3483,6 +3934,11 @@
     }
   }
 #endif
+#if defined(HAS_RAWTORGBAROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RAWToRGBARow = RAWToRGBARow_SVE2;
+  }
+#endif
 #if defined(HAS_RAWTORGBAROW_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     RAWToRGBARow = RAWToRGBARow_RVV;
@@ -3542,7 +3998,7 @@
 #if defined(HAS_RGB565TOARGBROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
-    if (IS_ALIGNED(width, 8)) {
+    if (IS_ALIGNED(width, 16)) {
       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
     }
   }
@@ -3625,11 +4081,16 @@
 #if defined(HAS_ARGB1555TOARGBROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
-    if (IS_ALIGNED(width, 8)) {
+    if (IS_ALIGNED(width, 16)) {
       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
     }
   }
 #endif
+#if defined(HAS_ARGB1555TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGB1555ToARGBRow = ARGB1555ToARGBRow_SVE2;
+  }
+#endif
 #if defined(HAS_ARGB1555TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
@@ -4019,6 +4480,16 @@
     }
   }
 #endif
+#if defined(HAS_NV12TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    NV12ToARGBRow = NV12ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_NV12TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    NV12ToARGBRow = NV12ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_NV12TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
@@ -4109,6 +4580,16 @@
     }
   }
 #endif
+#if defined(HAS_NV21TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    NV21ToARGBRow = NV21ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_NV21TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    NV21ToARGBRow = NV21ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_NV21TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
@@ -4242,6 +4723,16 @@
     }
   }
 #endif
+#if defined(HAS_NV12TORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    NV12ToRGB24Row = NV12ToRGB24Row_SVE2;
+  }
+#endif
+#if defined(HAS_NV12TORGB24ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    NV12ToRGB24Row = NV12ToRGB24Row_SME;
+  }
+#endif
 #if defined(HAS_NV12TORGB24ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
@@ -4308,6 +4799,16 @@
     }
   }
 #endif
+#if defined(HAS_NV21TORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    NV21ToRGB24Row = NV21ToRGB24Row_SVE2;
+  }
+#endif
+#if defined(HAS_NV21TORGB24ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    NV21ToRGB24Row = NV21ToRGB24Row_SME;
+  }
+#endif
 #if defined(HAS_NV21TORGB24ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
@@ -4455,14 +4956,15 @@
   return 0;
 }
 
-// Convert YUY2 to ARGB.
+// Convert YUY2 to ARGB with matrix.
 LIBYUV_API
-int YUY2ToARGB(const uint8_t* src_yuy2,
-               int src_stride_yuy2,
-               uint8_t* dst_argb,
-               int dst_stride_argb,
-               int width,
-               int height) {
+int YUY2ToARGBMatrix(const uint8_t* src_yuy2,
+                     int src_stride_yuy2,
+                     uint8_t* dst_argb,
+                     int dst_stride_argb,
+                     const struct YuvConstants* yuvconstants,
+                     int width,
+                     int height) {
   int y;
   void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants, int width) =
@@ -4506,6 +5008,16 @@
     }
   }
 #endif
+#if defined(HAS_YUY2TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    YUY2ToARGBRow = YUY2ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_YUY2TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    YUY2ToARGBRow = YUY2ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_YUY2TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
@@ -4523,21 +5035,34 @@
   }
 #endif
   for (y = 0; y < height; ++y) {
-    YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
+    YUY2ToARGBRow(src_yuy2, dst_argb, yuvconstants, width);
     src_yuy2 += src_stride_yuy2;
     dst_argb += dst_stride_argb;
   }
   return 0;
 }
 
-// Convert UYVY to ARGB.
+// Convert YUY2 to ARGB.
 LIBYUV_API
-int UYVYToARGB(const uint8_t* src_uyvy,
-               int src_stride_uyvy,
+int YUY2ToARGB(const uint8_t* src_yuy2,
+               int src_stride_yuy2,
                uint8_t* dst_argb,
                int dst_stride_argb,
                int width,
                int height) {
+  return YUY2ToARGBMatrix(src_yuy2, src_stride_yuy2, dst_argb, dst_stride_argb,
+                          &kYuvI601Constants, width, height);
+}
+
+// Convert UYVY to ARGB with matrix.
+LIBYUV_API
+int UYVYToARGBMatrix(const uint8_t* src_uyvy,
+                     int src_stride_uyvy,
+                     uint8_t* dst_argb,
+                     int dst_stride_argb,
+                     const struct YuvConstants* yuvconstants,
+                     int width,
+                     int height) {
   int y;
   void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants, int width) =
@@ -4581,6 +5106,16 @@
     }
   }
 #endif
+#if defined(HAS_UYVYTOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    UYVYToARGBRow = UYVYToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_UYVYTOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    UYVYToARGBRow = UYVYToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_UYVYTOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
@@ -4598,12 +5133,25 @@
   }
 #endif
   for (y = 0; y < height; ++y) {
-    UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
+    UYVYToARGBRow(src_uyvy, dst_argb, yuvconstants, width);
     src_uyvy += src_stride_uyvy;
     dst_argb += dst_stride_argb;
   }
   return 0;
 }
+
+// Convert UYVY to ARGB.
+LIBYUV_API
+int UYVYToARGB(const uint8_t* src_uyvy,
+               int src_stride_uyvy,
+               uint8_t* dst_argb,
+               int dst_stride_argb,
+               int width,
+               int height) {
+  return UYVYToARGBMatrix(src_uyvy, src_stride_uyvy, dst_argb, dst_stride_argb,
+                          &kYuvI601Constants, width, height);
+}
+
 static void WeavePixels(const uint8_t* src_u,
                         const uint8_t* src_v,
                         int src_pixel_stride_uv,
@@ -4775,6 +5323,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGBAROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGBARow = I422ToRGBARow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGBAROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGBARow = I422ToRGBARow_SME;
+  }
+#endif
 #if defined(HAS_I422TORGBAROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGBARow = I422ToRGBARow_Any_MSA;
@@ -5003,6 +5561,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGBAROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGBARow = I422ToRGBARow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGBAROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGBARow = I422ToRGBARow_SME;
+  }
+#endif
 #if defined(HAS_I422TORGBAROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGBARow = I422ToRGBARow_Any_MSA;
@@ -5133,6 +5701,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGB24Row = I422ToRGB24Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGB24ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGB24Row = I422ToRGB24Row_SME;
+  }
+#endif
 #if defined(HAS_I422TORGB24ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
@@ -5335,6 +5913,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGB24Row = I422ToRGB24Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGB24ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGB24Row = I422ToRGB24Row_SME;
+  }
+#endif
 #if defined(HAS_I422TORGB24ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
@@ -5462,6 +6050,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGB1555ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGB1555Row = I422ToARGB1555Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGB1555ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGB1555Row = I422ToARGB1555Row_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGB1555ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
@@ -5551,6 +6149,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGB4444ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGB4444Row = I422ToARGB4444Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGB4444ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGB4444Row = I422ToARGB4444Row_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGB4444ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
@@ -5641,6 +6249,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGB565ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGB565Row = I422ToRGB565Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGB565ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGB565Row = I422ToRGB565Row_SME;
+  }
+#endif
 #if defined(HAS_I422TORGB565ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
@@ -5781,6 +6399,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TORGB565ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToRGB565Row = I422ToRGB565Row_SVE2;
+  }
+#endif
+#if defined(HAS_I422TORGB565ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToRGB565Row = I422ToRGB565Row_SME;
+  }
+#endif
 #if defined(HAS_I422TORGB565ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
@@ -5904,6 +6532,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGBRow = I422ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGBRow = I422ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGBRow = I422ToARGBRow_Any_MSA;
@@ -5957,6 +6595,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTORGB565DITHERROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SVE2;
+  }
+#endif
 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
@@ -6049,6 +6692,14 @@
     }
   }
 #endif
+#if defined(HAS_I422TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I422ToAR30Row = I422ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I422ToAR30Row = I422ToAR30Row_NEON;
+    }
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
@@ -6185,6 +6836,16 @@
     }
   }
 #endif
+#if defined(HAS_I444TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444ToARGBRow = I444ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444ToARGBRow = I444ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444ToARGBRow = I444ToARGBRow_Any_MSA;
@@ -6332,6 +6993,16 @@
     }
   }
 #endif
+#if defined(HAS_I444TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444ToARGBRow = I444ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444ToARGBRow = I444ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444ToARGBRow = I444ToARGBRow_Any_MSA;
@@ -6582,6 +7253,24 @@
     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
     dst_stride_ar30 = -dst_stride_ar30;
   }
+#if defined(HAS_I410TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToAR30Row = I410ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToAR30Row = I410ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToAR30Row = I410ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToAR30Row = I410ToAR30Row_SME;
+  }
+#endif
 #if defined(HAS_I410TOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410ToAR30Row = I410ToAR30Row_Any_SSSE3;
@@ -6688,6 +7377,24 @@
     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
     dst_stride_ar30 = -dst_stride_ar30;
   }
+#if defined(HAS_I410TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToAR30Row = I410ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToAR30Row = I410ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToAR30Row = I410ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToAR30Row = I410ToAR30Row_SME;
+  }
+#endif
 #if defined(HAS_I410TOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410ToAR30Row = I410ToAR30Row_Any_SSSE3;
@@ -6781,6 +7488,24 @@
     }
   }
 #endif
+#if defined(HAS_I410TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToARGBRow = I410ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToARGBRow = I410ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToARGBRow = I410ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToARGBRow = I410ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410TOARGBROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     I410ToARGBRow = I410ToARGBRow_Any_AVX2;
@@ -6886,6 +7611,24 @@
     }
   }
 #endif
+#if defined(HAS_I410TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410ToARGBRow = I410ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410ToARGBRow = I410ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410ToARGBRow = I410ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410ToARGBRow = I410ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410TOARGBROW_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     I410ToARGBRow = I410ToARGBRow_Any_AVX2;
@@ -6996,6 +7739,16 @@
     }
   }
 #endif
+#if defined(HAS_I444ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444ALPHATOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444AlphaToARGBRow = I444AlphaToARGBRow_Any_MSA;
@@ -7054,6 +7807,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
 #if defined(HAS_SCALEROWUP2_BILINEAR_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
@@ -7206,6 +7975,16 @@
     }
   }
 #endif
+#if defined(HAS_I444ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I444ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I444AlphaToARGBRow = I444AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I444ALPHATOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I444AlphaToARGBRow = I444AlphaToARGBRow_Any_MSA;
@@ -7264,6 +8043,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
 #if defined(HAS_SCALEROWUP2_LINEAR_SSE2)
   if (TestCpuFlag(kCpuHasSSE2)) {
@@ -7357,6 +8152,24 @@
     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     dst_stride_argb = -dst_stride_argb;
   }
+#if defined(HAS_I410ALPHATOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410AlphaToARGBRow = I410AlphaToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410ALPHATOARGBROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410AlphaToARGBRow = I410AlphaToARGBRow_Any_SSSE3;
@@ -7410,6 +8223,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
 #if defined(HAS_SCALEROWUP2_BILINEAR_12_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
@@ -7525,6 +8354,24 @@
     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     dst_stride_argb = -dst_stride_argb;
   }
+#if defined(HAS_I410ALPHATOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      I410AlphaToARGBRow = I410AlphaToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I410ALPHATOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I410AlphaToARGBRow = I410AlphaToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I410ALPHATOARGBROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     I410AlphaToARGBRow = I410AlphaToARGBRow_Any_SSSE3;
@@ -7578,6 +8425,22 @@
     ARGBAttenuateRow = ARGBAttenuateRow_RVV;
   }
 #endif
+#if defined(HAS_ARGBATTENUATEROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LSX;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBATTENUATEROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBAttenuateRow = ARGBAttenuateRow_Any_LASX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBAttenuateRow = ARGBAttenuateRow_LASX;
+    }
+  }
+#endif
 
 #if defined(HAS_SCALEROWUP2_LINEAR_12_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
@@ -7663,6 +8526,24 @@
     }
   }
 #endif
+#if defined(HAS_P410TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P410ToARGBRow = P410ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P410ToARGBRow = P410ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P410TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P410ToARGBRow = P410ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_P410TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P410ToARGBRow = P410ToARGBRow_SME;
+  }
+#endif
 
 #ifdef HAS_SCALEUVROWUP2_BILINEAR_16_SSE41
   if (TestCpuFlag(kCpuHasSSE41)) {
@@ -7756,6 +8637,24 @@
     }
   }
 #endif
+#if defined(HAS_P410TOARGBROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P410ToARGBRow = P410ToARGBRow_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P410ToARGBRow = P410ToARGBRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P410TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P410ToARGBRow = P410ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_P410TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P410ToARGBRow = P410ToARGBRow_SME;
+  }
+#endif
 
 #ifdef HAS_SCALEUVROWUP2_LINEAR_16_SSE41
   if (TestCpuFlag(kCpuHasSSE41)) {
@@ -7835,6 +8734,24 @@
     }
   }
 #endif
+#if defined(HAS_P410TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P410ToAR30Row = P410ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P410ToAR30Row = P410ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P410TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P410ToAR30Row = P410ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_P410TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P410ToAR30Row = P410ToAR30Row_SME;
+  }
+#endif
 
 #ifdef HAS_SCALEUVROWUP2_BILINEAR_16_SSE41
   if (TestCpuFlag(kCpuHasSSE41)) {
@@ -7928,6 +8845,24 @@
     }
   }
 #endif
+#if defined(HAS_P410TOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    P410ToAR30Row = P410ToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      P410ToAR30Row = P410ToAR30Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_P410TOAR30ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    P410ToAR30Row = P410ToAR30Row_SVE2;
+  }
+#endif
+#if defined(HAS_P410TOAR30ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    P410ToAR30Row = P410ToAR30Row_SME;
+  }
+#endif
 
 #ifdef HAS_SCALEUVROWUP2_LINEAR_16_SSE41
   if (TestCpuFlag(kCpuHasSSE41)) {
diff --git a/source/convert_from.cc b/source/convert_from.cc
index e69da9e..f118702 100644
--- a/source/convert_from.cc
+++ b/source/convert_from.cc
@@ -30,8 +30,6 @@
 }
 
 // I420 To any I4xx YUV format with mirroring.
-// TODO(fbarchard): Consider kFilterNone for Y, or CopyPlane
-
 static int I420ToI4xx(const uint8_t* src_y,
                       int src_stride_y,
                       const uint8_t* src_u,
@@ -48,21 +46,17 @@
                       int src_y_height,
                       int dst_uv_width,
                       int dst_uv_height) {
-  const int dst_y_width = Abs(src_y_width);
-  const int dst_y_height = Abs(src_y_height);
   const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
   const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
   int r;
-  if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v ||
+      src_y_width <= 0 || src_y_height == 0 || dst_uv_width <= 0 ||
       dst_uv_height <= 0) {
     return -1;
   }
   if (dst_y) {
-    r = ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
-                   dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_y_width,
+              src_y_height);
   }
   r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
                  dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
@@ -231,25 +225,22 @@
                int width,
                int height) {
   int r;
-  if (width == 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                      Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1),
-                    SUBSAMPLE(height, 1, 1), dst_u, dst_stride_u, Abs(width),
+                    SUBSAMPLE(height, 1, 1), dst_u, dst_stride_u, width,
                     Abs(height), kFilterBilinear);
   if (r != 0) {
     return r;
   }
   r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1),
-                    SUBSAMPLE(height, 1, 1), dst_v, dst_stride_v, Abs(width),
+                    SUBSAMPLE(height, 1, 1), dst_v, dst_stride_v, width,
                     Abs(height), kFilterBilinear);
   return r;
 }
@@ -271,24 +262,21 @@
                int width,
                int height) {
   int r;
-  if (width == 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                      Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
-                    dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
+                    dst_stride_u, width, Abs(height), kFilterBilinear);
   if (r != 0) {
     return r;
   }
   r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
-                    dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
+                    dst_stride_v, width, Abs(height), kFilterBilinear);
   return r;
 }
 
@@ -310,24 +298,21 @@
                int width,
                int height) {
   int r;
-  if (width == 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+      height == 0) {
     return -1;
   }
 
   if (dst_y) {
-    r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
-                   Abs(width), Abs(height), kFilterBilinear);
-    if (r != 0) {
-      return r;
-    }
+    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   }
   r = ScalePlane(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
-                 dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
+                 dst_stride_u, width, Abs(height), kFilterBilinear);
   if (r != 0) {
     return r;
   }
   r = ScalePlane(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
-                 dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
+                 dst_stride_v, width, Abs(height), kFilterBilinear);
   return r;
 }
 
@@ -342,12 +327,6 @@
   if (!src_y || !dst_y || width <= 0 || height == 0) {
     return -1;
   }
-  // Negative height means invert the image.
-  if (height < 0) {
-    height = -height;
-    src_y = src_y + (height - 1) * src_stride_y;
-    src_stride_y = -src_stride_y;
-  }
   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   return 0;
 }
@@ -699,7 +678,8 @@
                int height) {
   int halfwidth = (width + 1) / 2;
   int halfheight = (height + 1) / 2;
-  if (!src_y || !src_u || !src_v || !dst_uv || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
+      height == 0) {
     return -1;
   }
   // Negative height means invert the image.
diff --git a/source/convert_from_argb.cc b/source/convert_from_argb.cc
index b45de8c..8d2e8d0 100644
--- a/source/convert_from_argb.cc
+++ b/source/convert_from_argb.cc
@@ -60,6 +60,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUV444ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUV444Row = ARGBToUV444Row_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUV444ROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
@@ -68,6 +76,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUV444ROW_NEON_I8MM)
+  if (TestCpuFlag(kCpuHasNeonI8MM)) {
+    ARGBToUV444Row = ARGBToUV444Row_Any_NEON_I8MM;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUV444Row = ARGBToUV444Row_NEON_I8MM;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUV444ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToUV444Row = ARGBToUV444Row_Any_MSA;
@@ -116,6 +132,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -231,6 +255,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -239,6 +271,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -331,6 +371,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -339,6 +387,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYRow = ARGBToYRow_Any_SSSE3;
@@ -438,6 +494,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_ = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow_ = MergeUVRow_Any_MSA;
@@ -553,6 +614,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -561,6 +630,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -638,6 +715,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_ = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow_ = MergeUVRow_Any_MSA;
@@ -752,6 +834,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYRow = ABGRToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYRow = ABGRToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ABGRToUVRow = ABGRToUVRow_Any_NEON;
@@ -760,6 +850,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ABGRToUVRow = ABGRToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ABGRToUVRow = ABGRToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYRow = ABGRToYRow_Any_MSA;
@@ -825,6 +923,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_ = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow_ = MergeUVRow_Any_MSA;
@@ -940,6 +1043,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYRow = ABGRToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYRow = ABGRToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ABGRToUVRow = ABGRToUVRow_Any_NEON;
@@ -948,6 +1059,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ABGRToUVRow = ABGRToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ABGRToUVRow = ABGRToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYRow = ABGRToYRow_Any_MSA;
@@ -1013,6 +1132,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_ = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow_ = MergeUVRow_Any_MSA;
@@ -1133,6 +1257,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -1141,6 +1273,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -1329,6 +1469,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVRow = ARGBToUVRow_Any_NEON;
@@ -1337,6 +1485,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVRow = ARGBToUVRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVRow = ARGBToUVRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -1501,6 +1657,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYRow = ARGBToYRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYRow = ARGBToYRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYRow = ARGBToYRow_Any_MSA;
@@ -1654,6 +1818,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToRGB24Row = ARGBToRGB24Row_SVE2;
+  }
+#endif
 #if defined(HAS_ARGBTORGB24ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToRGB24Row = ARGBToRGB24Row_Any_MSA;
@@ -1741,6 +1910,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTORAWROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToRAWRow = ARGBToRAWRow_SVE2;
+  }
+#endif
 #if defined(HAS_ARGBTORAWROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToRAWRow = ARGBToRAWRow_Any_MSA;
@@ -1832,6 +2006,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTORGB565DITHERROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SVE2;
+  }
+#endif
 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
@@ -1917,6 +2096,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTORGB565ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToRGB565Row = ARGBToRGB565Row_SVE2;
+  }
+#endif
 #if defined(HAS_ARGBTORGB565ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToRGB565Row = ARGBToRGB565Row_Any_MSA;
@@ -2140,6 +2324,14 @@
     height = 1;
     src_stride_abgr = dst_stride_ar30 = 0;
   }
+#if defined(HAS_ABGRTOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ABGRToAR30Row = ABGRToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      ABGRToAR30Row = ABGRToAR30Row_NEON;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ABGRToAR30Row = ABGRToAR30Row_Any_SSSE3;
@@ -2189,6 +2381,14 @@
     height = 1;
     src_stride_argb = dst_stride_ar30 = 0;
   }
+#if defined(HAS_ARGBTOAR30ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToAR30Row = ARGBToAR30Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToAR30Row = ARGBToAR30Row_NEON;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOAR30ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToAR30Row = ARGBToAR30Row_Any_SSSE3;
@@ -2213,6 +2413,167 @@
   return 0;
 }
 
+// ARGB little endian (bgra in memory) to J444
+LIBYUV_API
+int ARGBToJ444(const uint8_t* src_argb,
+               int src_stride_argb,
+               uint8_t* dst_y,
+               int dst_stride_y,
+               uint8_t* dst_u,
+               int dst_stride_u,
+               uint8_t* dst_v,
+               int dst_stride_v,
+               int width,
+               int height) {
+  int y;
+  void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
+      ARGBToYJRow_C;
+  void (*ARGBToUVJ444Row)(const uint8_t* src_argb, uint8_t* dst_u,
+                          uint8_t* dst_v, int width) = ARGBToUVJ444Row_C;
+  if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
+    return -1;
+  }
+  if (height < 0) {
+    height = -height;
+    src_argb = src_argb + (height - 1) * src_stride_argb;
+    src_stride_argb = -src_stride_argb;
+  }
+  // Coalesce rows.
+  if (src_stride_argb == width * 4 && dst_stride_y == width &&
+      dst_stride_u == width && dst_stride_v == width) {
+    width *= height;
+    height = 1;
+    src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
+  }
+#if defined(HAS_ARGBTOUVJ444ROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_NEON_I8MM)
+  if (TestCpuFlag(kCpuHasNeonI8MM)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_NEON_I8MM;
+    if (IS_ALIGNED(width, 8)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_NEON_I8MM;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOUVJ444ROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToUVJ444Row = ARGBToUVJ444Row_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToUVJ444Row = ARGBToUVJ444Row_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_SSSE3)
+  if (TestCpuFlag(kCpuHasSSSE3)) {
+    ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_SSSE3;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    ARGBToYJRow = ARGBToYJRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYJRow = ARGBToYJRow_AVX2;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_MSA)
+  if (TestCpuFlag(kCpuHasMSA)) {
+    ARGBToYJRow = ARGBToYJRow_Any_MSA;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_MSA;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_LSX)
+  if (TestCpuFlag(kCpuHasLSX)) {
+    ARGBToYJRow = ARGBToYJRow_Any_LSX;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_LSX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_LASX)
+  if (TestCpuFlag(kCpuHasLASX)) {
+    ARGBToYJRow = ARGBToYJRow_Any_LASX;
+    if (IS_ALIGNED(width, 32)) {
+      ARGBToYJRow = ARGBToYJRow_LASX;
+    }
+  }
+#endif
+#if defined(HAS_ARGBTOYJROW_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    ARGBToYJRow = ARGBToYJRow_RVV;
+  }
+#endif
+
+  for (y = 0; y < height; ++y) {
+    ARGBToUVJ444Row(src_argb, dst_u, dst_v, width);
+    ARGBToYJRow(src_argb, dst_y, width);
+    src_argb += src_stride_argb;
+    dst_y += dst_stride_y;
+    dst_u += dst_stride_u;
+    dst_v += dst_stride_v;
+  }
+  return 0;
+}
+
 // Convert ARGB to J420. (JPeg full range I420).
 LIBYUV_API
 int ARGBToJ420(const uint8_t* src_argb,
@@ -2248,6 +2609,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVJROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
@@ -2256,6 +2625,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVJROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVJRow = ARGBToUVJRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVJRow = ARGBToUVJRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYJROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
@@ -2416,6 +2793,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOUVJROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
@@ -2424,6 +2809,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOUVJROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ARGBToUVJRow = ARGBToUVJRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ARGBToUVJRow = ARGBToUVJRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYJROW_MSA) && defined(HAS_ARGBTOUVJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYJRow = ARGBToYJRow_Any_MSA;
@@ -2522,6 +2915,14 @@
     }
   }
 #endif
+#if defined(HAS_ARGBTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ARGBToYJRow = ARGBToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ARGBToYJRow = ARGBToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBToYJRow = ARGBToYJRow_Any_MSA;
@@ -2593,6 +2994,14 @@
     }
   }
 #endif
+#if defined(HAS_RGBATOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    RGBAToYJRow = RGBAToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      RGBAToYJRow = RGBAToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_RGBATOYJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RGBAToYJRow = RGBAToYJRow_Any_MSA;
@@ -2698,6 +3107,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYJRow = ABGRToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYJRow = ABGRToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOUVJROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ABGRToUVJRow = ABGRToUVJRow_Any_NEON;
@@ -2706,6 +3123,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOUVJROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ABGRToUVJRow = ABGRToUVJRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ABGRToUVJRow = ABGRToUVJRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYJROW_MSA) && defined(HAS_ABGRTOUVJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYJRow = ABGRToYJRow_Any_MSA;
@@ -2828,6 +3253,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYJRow = ABGRToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYJRow = ABGRToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOUVJROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ABGRToUVJRow = ABGRToUVJRow_Any_NEON;
@@ -2836,6 +3269,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOUVJROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    ABGRToUVJRow = ABGRToUVJRow_Any_SVE2;
+    if (IS_ALIGNED(width, 2)) {
+      ABGRToUVJRow = ABGRToUVJRow_SVE2;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYJROW_MSA) && defined(HAS_ABGRTOUVJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYJRow = ABGRToYJRow_Any_MSA;
@@ -2930,6 +3371,14 @@
     }
   }
 #endif
+#if defined(HAS_ABGRTOYJROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd)) {
+    ABGRToYJRow = ABGRToYJRow_Any_NEON_DotProd;
+    if (IS_ALIGNED(width, 16)) {
+      ABGRToYJRow = ABGRToYJRow_NEON_DotProd;
+    }
+  }
+#endif
 #if defined(HAS_ABGRTOYJROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ABGRToYJRow = ABGRToYJRow_Any_MSA;
@@ -3197,6 +3646,14 @@
     }
   }
 #endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    RAWToARGBRow = RAWToARGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      RAWToARGBRow = RAWToARGBRow_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_ARGBTOYJROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
@@ -3262,6 +3719,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_ = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow_ = MergeUVRow_Any_MSA;
diff --git a/source/convert_to_argb.cc b/source/convert_to_argb.cc
index 84df16c..72d21b0 100644
--- a/source/convert_to_argb.cc
+++ b/source/convert_to_argb.cc
@@ -10,6 +10,10 @@
 
 #include "libyuv/convert_argb.h"
 
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
 #include "libyuv/cpu_id.h"
 #ifdef HAVE_JPEG
 #include "libyuv/mjpeg_decoder.h"
@@ -66,7 +70,8 @@
   uint8_t* rotate_buffer = NULL;
   int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
 
-  if (dst_argb == NULL || sample == NULL || src_width <= 0 || crop_width <= 0 ||
+  if (dst_argb == NULL || sample == NULL || src_width <= 0 ||
+      src_width > INT_MAX / 4 || crop_width <= 0 || crop_width > INT_MAX / 4 ||
       src_height == 0 || crop_height == 0) {
     return -1;
   }
@@ -75,8 +80,12 @@
   }
 
   if (need_buf) {
-    int argb_size = crop_width * 4 * abs_crop_height;
-    rotate_buffer = (uint8_t*)malloc(argb_size); /* NOLINT */
+    const uint64_t rotate_buffer_size =
+        (uint64_t)crop_width * 4 * abs_crop_height;
+    if (rotate_buffer_size > SIZE_MAX) {
+      return -1;  // Invalid size.
+    }
+    rotate_buffer = (uint8_t*)malloc((size_t)rotate_buffer_size);
     if (!rotate_buffer) {
       return 1;  // Out of memory runtime error.
     }
diff --git a/source/convert_to_i420.cc b/source/convert_to_i420.cc
index 5869ecd..aab071e 100644
--- a/source/convert_to_i420.cc
+++ b/source/convert_to_i420.cc
@@ -8,10 +8,13 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <stdlib.h>
-
 #include "libyuv/convert.h"
 
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
 #include "libyuv/video_common.h"
 
 #ifdef __cplusplus
@@ -46,7 +49,6 @@
   const uint8_t* src;
   const uint8_t* src_uv;
   const int abs_src_height = (src_height < 0) ? -src_height : src_height;
-  // TODO(nisse): Why allow crop_height < 0?
   const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
   int r = 0;
   LIBYUV_BOOL need_buf =
@@ -64,7 +66,8 @@
       (src_height < 0) ? -abs_crop_height : abs_crop_height;
 
   if (!dst_y || !dst_u || !dst_v || !sample || src_width <= 0 ||
-      crop_width <= 0 || src_height == 0 || crop_height == 0) {
+      src_width > INT_MAX / 4 || crop_width <= 0 || src_height == 0 ||
+      crop_height == 0) {
     return -1;
   }
 
@@ -76,7 +79,12 @@
   if (need_buf) {
     int y_size = crop_width * abs_crop_height;
     int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
-    rotate_buffer = (uint8_t*)malloc(y_size + uv_size * 2); /* NOLINT */
+    const uint64_t rotate_buffer_size =
+        (uint64_t)y_size + (uint64_t)uv_size * 2;
+    if (rotate_buffer_size > SIZE_MAX) {
+      return -1;  // Invalid size.
+    }
+    rotate_buffer = (uint8_t*)malloc((size_t)rotate_buffer_size);
     if (!rotate_buffer) {
       return 1;  // Out of memory runtime error.
     }
diff --git a/source/cpu_id.cc b/source/cpu_id.cc
index eedce16..e4acbec 100644
--- a/source/cpu_id.cc
+++ b/source/cpu_id.cc
@@ -23,6 +23,22 @@
 #include <stdio.h>  // For fopen()
 #include <string.h>
 
+#if defined(__linux__) && defined(__aarch64__)
+#include <sys/auxv.h>  // For getauxval()
+#endif
+
+#if defined(_WIN32) && defined(__aarch64__)
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#undef WIN32_EXTRA_LEAN
+#define WIN32_EXTRA_LEAN
+#include <windows.h>  // For IsProcessorFeaturePresent()
+#endif
+
+#if defined(__APPLE__) && defined(__aarch64__)
+#include <sys/sysctl.h>  // For sysctlbyname()
+#endif
+
 #ifdef __cplusplus
 namespace libyuv {
 extern "C" {
@@ -132,6 +148,13 @@
 #pragma optimize("g", on)
 #endif
 
+static int cpuinfo_search(const char* cpuinfo_line,
+                          const char* needle,
+                          int needle_len) {
+  const char* p = strstr(cpuinfo_line, needle);
+  return p && (p[needle_len] == ' ' || p[needle_len] == '\n');
+}
+
 // Based on libvpx arm_cpudetect.c
 // For Arm, but public to allow testing on any CPU
 LIBYUV_API SAFEBUFFERS int ArmCpuCaps(const char* cpuinfo_name) {
@@ -143,25 +166,118 @@
     return kCpuHasNEON;
   }
   memset(cpuinfo_line, 0, sizeof(cpuinfo_line));
+  int features = 0;
   while (fgets(cpuinfo_line, sizeof(cpuinfo_line), f)) {
     if (memcmp(cpuinfo_line, "Features", 8) == 0) {
-      char* p = strstr(cpuinfo_line, " neon");
-      if (p && (p[5] == ' ' || p[5] == '\n')) {
-        fclose(f);
-        return kCpuHasNEON;
-      }
-      // aarch64 uses asimd for Neon.
-      p = strstr(cpuinfo_line, " asimd");
-      if (p) {
-        fclose(f);
-        return kCpuHasNEON;
+      if (cpuinfo_search(cpuinfo_line, " neon", 5)) {
+        features |= kCpuHasNEON;
       }
     }
   }
   fclose(f);
-  return 0;
+  return features;
 }
 
+#ifdef __aarch64__
+#ifdef __linux__
+// Define hwcap values ourselves: building with an old auxv header where these
+// hwcap values are not defined should not prevent features from being enabled.
+#define YUV_AARCH64_HWCAP_ASIMDDP (1 << 20)
+#define YUV_AARCH64_HWCAP_SVE (1 << 22)
+#define YUV_AARCH64_HWCAP2_SVE2 (1 << 1)
+#define YUV_AARCH64_HWCAP2_I8MM (1 << 13)
+#define YUV_AARCH64_HWCAP2_SME (1 << 23)
+
+// For AArch64, but public to allow testing on any CPU.
+LIBYUV_API SAFEBUFFERS int AArch64CpuCaps(unsigned long hwcap,
+                                          unsigned long hwcap2) {
+  // Neon is mandatory on AArch64, so enable regardless of hwcaps.
+  int features = kCpuHasNEON;
+
+  // Don't try to enable later extensions unless earlier extensions are also
+  // reported available. Some of these constraints aren't strictly required by
+  // the architecture, but are satisfied by all micro-architectures of
+  // interest. This also avoids an issue on some emulators where true
+  // architectural constraints are not satisfied, e.g. SVE2 may be reported as
+  // available while SVE is not.
+  if (hwcap & YUV_AARCH64_HWCAP_ASIMDDP) {
+    features |= kCpuHasNeonDotProd;
+    if (hwcap2 & YUV_AARCH64_HWCAP2_I8MM) {
+      features |= kCpuHasNeonI8MM;
+      if (hwcap & YUV_AARCH64_HWCAP_SVE) {
+        features |= kCpuHasSVE;
+        if (hwcap2 & YUV_AARCH64_HWCAP2_SVE2) {
+          features |= kCpuHasSVE2;
+          if (hwcap2 & YUV_AARCH64_HWCAP2_SME) {
+            features |= kCpuHasSME;
+          }
+        }
+      }
+    }
+  }
+  return features;
+}
+
+#elif defined(_WIN32)
+// For AArch64, but public to allow testing on any CPU.
+LIBYUV_API SAFEBUFFERS int AArch64CpuCaps() {
+  // Neon is mandatory on AArch64, so enable unconditionally.
+  int features = kCpuHasNEON;
+
+  // For more information on IsProcessorFeaturePresent(), see:
+  // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent#parameters
+#ifdef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
+  if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {
+    features |= kCpuHasNeonDotProd;
+  }
+#endif
+  // No Neon I8MM or SVE feature detection available here at time of writing.
+  return features;
+}
+
+#elif defined(__APPLE__)
+static bool have_feature(const char* feature) {
+  // For more information on sysctlbyname(), see:
+  // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
+  int64_t feature_present = 0;
+  size_t size = sizeof(feature_present);
+  if (sysctlbyname(feature, &feature_present, &size, NULL, 0) != 0) {
+    return false;
+  }
+  return feature_present;
+}
+
+// For AArch64, but public to allow testing on any CPU.
+LIBYUV_API SAFEBUFFERS int AArch64CpuCaps() {
+  // Neon is mandatory on AArch64, so enable unconditionally.
+  int features = kCpuHasNEON;
+
+  if (have_feature("hw.optional.arm.FEAT_DotProd")) {
+    features |= kCpuHasNeonDotProd;
+    if (have_feature("hw.optional.arm.FEAT_I8MM")) {
+      features |= kCpuHasNeonI8MM;
+      if (have_feature("hw.optional.arm.FEAT_SME2")) {
+        features |= kCpuHasSME;
+      }
+    }
+  }
+  // No SVE feature detection available here at time of writing.
+  return features;
+}
+
+#else  // !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__)
+// For AArch64, but public to allow testing on any CPU.
+LIBYUV_API SAFEBUFFERS int AArch64CpuCaps() {
+  // Neon is mandatory on AArch64, so enable unconditionally.
+  int features = kCpuHasNEON;
+
+  // TODO(libyuv:980) support feature detection on other platforms.
+
+  return features;
+}
+#endif
+#endif  // defined(__aarch64__)
+
 LIBYUV_API SAFEBUFFERS int RiscvCpuCaps(const char* cpuinfo_name) {
   char cpuinfo_line[512];
   int flag = 0;
@@ -293,17 +409,24 @@
   int cpu_info1[4] = {0, 0, 0, 0};
   int cpu_info7[4] = {0, 0, 0, 0};
   int cpu_einfo7[4] = {0, 0, 0, 0};
+  int cpu_info24[4] = {0, 0, 0, 0};
+  int cpu_amdinfo21[4] = {0, 0, 0, 0};
   CpuId(0, 0, cpu_info0);
   CpuId(1, 0, cpu_info1);
   if (cpu_info0[0] >= 7) {
     CpuId(7, 0, cpu_info7);
     CpuId(7, 1, cpu_einfo7);
+    CpuId(0x80000021, 0, cpu_amdinfo21);
+  }
+  if (cpu_info0[0] >= 0x24) {
+    CpuId(0x24, 0, cpu_info24);
   }
   cpu_info = kCpuHasX86 | ((cpu_info1[3] & 0x04000000) ? kCpuHasSSE2 : 0) |
              ((cpu_info1[2] & 0x00000200) ? kCpuHasSSSE3 : 0) |
              ((cpu_info1[2] & 0x00080000) ? kCpuHasSSE41 : 0) |
              ((cpu_info1[2] & 0x00100000) ? kCpuHasSSE42 : 0) |
-             ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0);
+             ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0) |
+             ((cpu_info7[3] & 0x00000010) ? kCpuHasFSMR : 0);
 
   // AVX requires OS saves YMM registers.
   if (((cpu_info1[2] & 0x1c000000) == 0x1c000000) &&  // AVX and OSXSave
@@ -314,15 +437,21 @@
                 ((cpu_einfo7[0] & 0x00000010) ? kCpuHasAVXVNNI : 0) |
                 ((cpu_einfo7[3] & 0x00000010) ? kCpuHasAVXVNNIINT8 : 0);
 
+    cpu_info |= ((cpu_amdinfo21[0] & 0x00008000) ? kCpuHasERMS : 0);
+
     // Detect AVX512bw
     if ((GetXCR0() & 0xe0) == 0xe0) {
-      cpu_info |= (cpu_info7[1] & 0x40000000) ? kCpuHasAVX512BW : 0;
-      cpu_info |= (cpu_info7[1] & 0x80000000) ? kCpuHasAVX512VL : 0;
-      cpu_info |= (cpu_info7[2] & 0x00000002) ? kCpuHasAVX512VBMI : 0;
-      cpu_info |= (cpu_info7[2] & 0x00000040) ? kCpuHasAVX512VBMI2 : 0;
-      cpu_info |= (cpu_info7[2] & 0x00000800) ? kCpuHasAVX512VNNI : 0;
-      cpu_info |= (cpu_info7[2] & 0x00001000) ? kCpuHasAVX512VBITALG : 0;
-      cpu_info |= (cpu_einfo7[3] & 0x00080000) ? kCpuHasAVX10 : 0;
+      cpu_info |= ((cpu_info7[1] & 0x40000000) ? kCpuHasAVX512BW : 0) |
+                  ((cpu_info7[1] & 0x80000000) ? kCpuHasAVX512VL : 0) |
+                  ((cpu_info7[2] & 0x00000002) ? kCpuHasAVX512VBMI : 0) |
+                  ((cpu_info7[2] & 0x00000040) ? kCpuHasAVX512VBMI2 : 0) |
+                  ((cpu_info7[2] & 0x00000800) ? kCpuHasAVX512VNNI : 0) |
+                  ((cpu_info7[2] & 0x00001000) ? kCpuHasAVX512VBITALG : 0) |
+                  ((cpu_einfo7[3] & 0x00080000) ? kCpuHasAVX10 : 0) |
+                  ((cpu_info7[3] & 0x02000000) ? kCpuHasAMXINT8 : 0);
+      if (cpu_info0[0] >= 0x24 && (cpu_einfo7[3] & 0x00080000)) {
+        cpu_info |= ((cpu_info24[1] & 0xFF) >= 2) ? kCpuHasAVX10_2 : 0;
+      }
     }
   }
 #endif
@@ -334,21 +463,31 @@
   cpu_info = LoongarchCpuCaps();
   cpu_info |= kCpuHasLOONGARCH;
 #endif
-#if defined(__arm__) || defined(__aarch64__)
-// gcc -mfpu=neon defines __ARM_NEON__
-// __ARM_NEON__ generates code that requires Neon.  NaCL also requires Neon.
-// For Linux, /proc/cpuinfo can be tested but without that assume Neon.
-#if defined(__ARM_NEON__) || defined(__native_client__) || !defined(__linux__)
-  cpu_info = kCpuHasNEON;
-// For aarch64(arm64), /proc/cpuinfo's feature is not complete, e.g. no neon
-// flag in it.
-// So for aarch64, neon enabling is hard coded here.
-#endif
 #if defined(__aarch64__)
+#if defined(__linux__)
+  // getauxval is supported since Android SDK version 18, minimum at time of
+  // writing is 21, so should be safe to always use this. If getauxval is
+  // somehow disabled then getauxval returns 0, which will leave Neon enabled
+  // since Neon is mandatory on AArch64.
+  unsigned long hwcap = getauxval(AT_HWCAP);
+  unsigned long hwcap2 = getauxval(AT_HWCAP2);
+  cpu_info = AArch64CpuCaps(hwcap, hwcap2);
+#else
+  cpu_info = AArch64CpuCaps();
+#endif
+  cpu_info |= kCpuHasARM;
+#endif  // __aarch64__
+#if defined(__arm__)
+  // gcc -mfpu=neon defines __ARM_NEON__
+  // __ARM_NEON__ generates code that requires Neon.  NaCL also requires Neon.
+  // For Linux, /proc/cpuinfo can be tested but without that assume Neon.
+  // Linux arm parse text file for neon detect.
+#if defined(__linux__)
+  cpu_info = ArmCpuCaps("/proc/cpuinfo");
+#elif defined(__ARM_NEON__)
   cpu_info = kCpuHasNEON;
 #else
-  // Linux arm parse text file for neon detect.
-  cpu_info = ArmCpuCaps("/proc/cpuinfo");
+  cpu_info = 0;
 #endif
   cpu_info |= kCpuHasARM;
 #endif  // __arm__
diff --git a/source/mjpeg_decoder.cc b/source/mjpeg_decoder.cc
index 0141da8..b93a849 100644
--- a/source/mjpeg_decoder.cc
+++ b/source/mjpeg_decoder.cc
@@ -13,8 +13,7 @@
 #ifdef HAVE_JPEG
 #include <assert.h>
 
-#if !defined(__pnacl__) && !defined(__CLR_VER) && \
-    !defined(COVERAGE_ENABLED) && !defined(TARGET_IPHONE_SIMULATOR)
+#if !defined(__pnacl__) && !defined(__CLR_VER) && !defined(COVERAGE_ENABLED)
 // Must be included before jpeglib.
 #include <setjmp.h>
 #define HAVE_SETJMP
diff --git a/source/planar_functions.cc b/source/planar_functions.cc
index 1c94e26..c2d4b67 100644
--- a/source/planar_functions.cc
+++ b/source/planar_functions.cc
@@ -14,9 +14,6 @@
 #include <string.h>  // for memset()
 
 #include "libyuv/cpu_id.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
 #include "libyuv/row.h"
 #include "libyuv/scale_row.h"  // for ScaleRowDown2
 
@@ -65,6 +62,11 @@
     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
   }
 #endif
+#if defined(HAS_COPYROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    CopyRow = IS_ALIGNED(width, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW;
+  }
+#endif
 #if defined(HAS_COPYROW_ERMS)
   if (TestCpuFlag(kCpuHasERMS)) {
     CopyRow = CopyRow_ERMS;
@@ -75,6 +77,11 @@
     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
   }
 #endif
+#if defined(HAS_COPYROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    CopyRow = CopyRow_SME;
+  }
+#endif
 #if defined(HAS_COPYROW_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     CopyRow = CopyRow_RVV;
@@ -136,6 +143,11 @@
     }
   }
 #endif
+#if defined(HAS_CONVERT16TO8ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    Convert16To8Row = Convert16To8Row_SME;
+  }
+#endif
 #if defined(HAS_CONVERT16TO8ROW_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     Convert16To8Row = Convert16To8Row_Any_SSSE3;
@@ -152,6 +164,14 @@
     }
   }
 #endif
+#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    Convert16To8Row = Convert16To8Row_Any_AVX512BW;
+    if (IS_ALIGNED(width, 64)) {
+      Convert16To8Row = Convert16To8Row_AVX512BW;
+    }
+  }
+#endif
 
   // Convert plane
   for (y = 0; y < height; ++y) {
@@ -214,6 +234,70 @@
   }
 }
 
+// Convert a plane of 8 bit data to 8 bit
+LIBYUV_API
+void Convert8To8Plane(const uint8_t* src_y,
+                      int src_stride_y,
+                      uint8_t* dst_y,
+                      int dst_stride_y,
+                      int scale,  // 220 for Y, 225 to UV
+                      int bias,   // 16
+                      int width,
+                      int height) {
+  int y;
+  void (*Convert8To8Row)(const uint8_t* src_y, uint8_t* dst_y, int scale,
+                         int bias, int width) = Convert8To8Row_C;
+
+  if (width <= 0 || height == 0) {
+    return;
+  }
+  // Negative height means invert the image.
+  if (height < 0) {
+    height = -height;
+    dst_y = dst_y + (height - 1) * dst_stride_y;
+    dst_stride_y = -dst_stride_y;
+  }
+  // Coalesce rows.
+  if (src_stride_y == width && dst_stride_y == width) {
+    width *= height;
+    height = 1;
+    src_stride_y = dst_stride_y = 0;
+  }
+#if defined(HAS_CONVERT8TO8ROW_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    Convert8To8Row = Convert8To8Row_Any_NEON;
+    if (IS_ALIGNED(width, 32)) {
+      Convert8To8Row = Convert8To8Row_NEON;
+    }
+  }
+#endif
+#if defined(HAS_CONVERT8TO8ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    Convert8To8Row = Convert8To8Row_SVE2;
+  }
+#endif
+#if defined(HAS_CONVERT8TO8ROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    Convert8To8Row = Convert8To8Row_SME;
+  }
+#endif
+#if defined(HAS_CONVERT8TO8ROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    Convert8To8Row = Convert8To8Row_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      Convert8To8Row = Convert8To8Row_AVX2;
+    }
+  }
+#endif
+
+  // Convert plane
+  for (y = 0; y < height; ++y) {
+    Convert8To8Row(src_y, dst_y, scale, bias, width);
+    src_y += src_stride_y;
+    dst_y += dst_stride_y;
+  }
+}
+
 // Copy I422.
 LIBYUV_API
 int I422Copy(const uint8_t* src_y,
@@ -625,6 +709,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow = MergeUVRow_SME;
+  }
+#endif
 #if defined(HAS_MERGEUVROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     MergeUVRow = MergeUVRow_Any_MSA;
@@ -764,6 +853,11 @@
     }
   }
 #endif
+#if defined(HAS_MERGEUVROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MergeUVRow_16 = MergeUVRow_16_SME;
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     // Merge a row of U and V into a row of UV.
@@ -819,6 +913,11 @@
     }
   }
 #endif
+#if defined(HAS_MULTIPLYROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    MultiplyRow_16 = MultiplyRow_16_SME;
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     MultiplyRow_16(src_y, dst_y, scale, width);
@@ -872,6 +971,11 @@
     }
   }
 #endif
+#if defined(HAS_DIVIDEROW_16_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    DivideRow = DivideRow_16_SVE2;
+  }
+#endif
 
   for (y = 0; y < height; ++y) {
     DivideRow(src_y, dst_y, scale, width);
@@ -1275,6 +1379,22 @@
     }
   }
 #endif
+#if defined(HAS_SPLITRGBROW_SSE41)
+  if (TestCpuFlag(kCpuHasSSE41)) {
+    SplitRGBRow = SplitRGBRow_Any_SSE41;
+    if (IS_ALIGNED(width, 16)) {
+      SplitRGBRow = SplitRGBRow_SSE41;
+    }
+  }
+#endif
+#if defined(HAS_SPLITRGBROW_AVX2)
+  if (TestCpuFlag(kCpuHasAVX2)) {
+    SplitRGBRow = SplitRGBRow_Any_AVX2;
+    if (IS_ALIGNED(width, 32)) {
+      SplitRGBRow = SplitRGBRow_AVX2;
+    }
+  }
+#endif
 #if defined(HAS_SPLITRGBROW_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     SplitRGBRow = SplitRGBRow_Any_NEON;
@@ -2597,7 +2717,7 @@
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
 
-  if (!src_y || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
+  if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
       height == 0) {
     return -1;
   }
@@ -2637,7 +2757,7 @@
   int halfwidth = (width + 1) >> 1;
   int halfheight = (height + 1) >> 1;
 
-  if (!src_y || !src_uv || !dst_uv || width <= 0 || height == 0) {
+  if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0) {
     return -1;
   }
 
@@ -3103,6 +3223,11 @@
     }
   }
 #endif
+#if defined(HAS_ARGBMULTIPLYROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ARGBMultiplyRow = ARGBMultiplyRow_SME;
+  }
+#endif
 #if defined(HAS_ARGBMULTIPLYROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ARGBMultiplyRow = ARGBMultiplyRow_Any_MSA;
@@ -3361,6 +3486,11 @@
     }
   }
 #endif
+#if defined(HAS_RAWTORGB24ROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    RAWToRGB24Row = RAWToRGB24Row_SVE2;
+  }
+#endif
 #if defined(HAS_RAWTORGB24ROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     RAWToRGB24Row = RAWToRGB24Row_Any_MSA;
@@ -3741,6 +3871,11 @@
     ARGBGrayRow = ARGBGrayRow_NEON;
   }
 #endif
+#if defined(HAS_ARGBGRAYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd) && IS_ALIGNED(width, 8)) {
+    ARGBGrayRow = ARGBGrayRow_NEON_DotProd;
+  }
+#endif
 #if defined(HAS_ARGBGRAYROW_MSA)
   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
     ARGBGrayRow = ARGBGrayRow_MSA;
@@ -3796,6 +3931,11 @@
     ARGBGrayRow = ARGBGrayRow_NEON;
   }
 #endif
+#if defined(HAS_ARGBGRAYROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd) && IS_ALIGNED(width, 8)) {
+    ARGBGrayRow = ARGBGrayRow_NEON_DotProd;
+  }
+#endif
 #if defined(HAS_ARGBGRAYROW_MSA)
   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
     ARGBGrayRow = ARGBGrayRow_MSA;
@@ -3849,6 +3989,11 @@
     ARGBSepiaRow = ARGBSepiaRow_NEON;
   }
 #endif
+#if defined(HAS_ARGBSEPIAROW_NEON_DOTPROD)
+  if (TestCpuFlag(kCpuHasNeonDotProd) && IS_ALIGNED(width, 8)) {
+    ARGBSepiaRow = ARGBSepiaRow_NEON_DotProd;
+  }
+#endif
 #if defined(HAS_ARGBSEPIAROW_MSA)
   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
     ARGBSepiaRow = ARGBSepiaRow_MSA;
@@ -3910,6 +4055,11 @@
     ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
   }
 #endif
+#if defined(HAS_ARGBCOLORMATRIXROW_NEON_I8MM)
+  if (TestCpuFlag(kCpuHasNeonI8MM) && IS_ALIGNED(width, 8)) {
+    ARGBColorMatrixRow = ARGBColorMatrixRow_NEON_I8MM;
+  }
+#endif
 #if defined(HAS_ARGBCOLORMATRIXROW_MSA)
   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
     ARGBColorMatrixRow = ARGBColorMatrixRow_MSA;
@@ -4357,6 +4507,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -4442,6 +4597,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow_16 = InterpolateRow_16_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_16_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow_16 = InterpolateRow_16_Any_MSA;
@@ -5152,14 +5312,26 @@
   }
 #endif
 #if defined(HAS_HALFFLOATROW_NEON)
-  if (TestCpuFlag(kCpuHasNEON)) {
-    HalfFloatRow =
-        (scale == 1.0f) ? HalfFloat1Row_Any_NEON : HalfFloatRow_Any_NEON;
-    if (IS_ALIGNED(width, 8)) {
-      HalfFloatRow = (scale == 1.0f) ? HalfFloat1Row_NEON : HalfFloatRow_NEON;
+  if (TestCpuFlag(kCpuHasNEON)
+#if defined(__arm__)
+      // When scale is 1/65535 the scale * 2^-112 used to convert is a denormal.
+      // But when Neon vmul is asked to multiply a normal float by that
+      // denormal scale, even though the result would have been normal, it
+      // flushes to zero.  The scalar version of vmul supports denormals.
+      && scale >= 1.0f / 4096.0f
+#endif
+  ) {
+    HalfFloatRow = HalfFloatRow_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      HalfFloatRow = HalfFloatRow_NEON;
     }
   }
 #endif
+#if defined(HAS_HALFFLOATROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    HalfFloatRow = scale == 1.0f ? HalfFloat1Row_SVE2 : HalfFloatRow_SVE2;
+  }
+#endif
 #if defined(HAS_HALFFLOATROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     HalfFloatRow = HalfFloatRow_Any_MSA;
@@ -5634,6 +5806,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
diff --git a/source/rotate.cc b/source/rotate.cc
index 3f8332c..1ef2e38 100644
--- a/source/rotate.cc
+++ b/source/rotate.cc
@@ -31,7 +31,12 @@
                     int width,
                     int height) {
   int i = height;
-#if defined(HAS_TRANSPOSEWX16_MSA) || defined(HAS_TRANSPOSEWX16_LSX)
+#if defined(HAS_TRANSPOSEWXH_SME)
+  void (*TransposeWxH)(const uint8_t* src, int src_stride, uint8_t* dst,
+                       int dst_stride, int width, int height) = NULL;
+#endif
+#if defined(HAS_TRANSPOSEWX16_MSA) || defined(HAS_TRANSPOSEWX16_LSX) || \
+    defined(HAS_TRANSPOSEWX16_NEON)
   void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst,
                         int dst_stride, int width) = TransposeWx16_C;
 #else
@@ -47,6 +52,19 @@
     }
   }
 #endif
+#if defined(HAS_TRANSPOSEWX16_NEON)
+  if (TestCpuFlag(kCpuHasNEON)) {
+    TransposeWx16 = TransposeWx16_Any_NEON;
+    if (IS_ALIGNED(width, 16)) {
+      TransposeWx16 = TransposeWx16_NEON;
+    }
+  }
+#endif
+#if defined(HAS_TRANSPOSEWXH_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    TransposeWxH = TransposeWxH_SME;
+  }
+#endif
 #if defined(HAS_TRANSPOSEWX8_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     TransposeWx8 = TransposeWx8_Any_SSSE3;
@@ -80,7 +98,14 @@
   }
 #endif
 
-#if defined(HAS_TRANSPOSEWX16_MSA) || defined(HAS_TRANSPOSEWX16_LSX)
+#if defined(HAS_TRANSPOSEWXH_SME)
+  if (TransposeWxH) {
+    TransposeWxH(src, src_stride, dst, dst_stride, width, height);
+    return;
+  }
+#endif
+#if defined(HAS_TRANSPOSEWX16_MSA) || defined(HAS_TRANSPOSEWX16_LSX) || \
+    defined(HAS_TRANSPOSEWX16_NEON)
   // Work across the source in 16x16 tiles
   while (i >= 16) {
     TransposeWx16(src, src_stride, dst, dst_stride, width);
@@ -209,6 +234,11 @@
     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
   }
 #endif
+#if defined(HAS_COPYROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    CopyRow = IS_ALIGNED(width, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW;
+  }
+#endif
 #if defined(HAS_COPYROW_ERMS)
   if (TestCpuFlag(kCpuHasERMS)) {
     CopyRow = CopyRow_ERMS;
@@ -219,6 +249,11 @@
     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
   }
 #endif
+#if defined(HAS_COPYROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    CopyRow = CopyRow_SME;
+  }
+#endif
 #if defined(HAS_COPYROW_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     CopyRow = CopyRow_RVV;
@@ -248,6 +283,11 @@
                       int width,
                       int height) {
   int i = height;
+#if defined(HAS_TRANSPOSEUVWXH_SME)
+  void (*TransposeUVWxH)(const uint8_t* src, int src_stride, uint8_t* dst_a,
+                         int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
+                         int width, int height) = TransposeUVWxH_C;
+#endif
 #if defined(HAS_TRANSPOSEUVWX16_MSA)
   void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a,
                           int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
@@ -279,7 +319,15 @@
 #else
 #if defined(HAS_TRANSPOSEUVWX8_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
-    TransposeUVWx8 = TransposeUVWx8_NEON;
+    TransposeUVWx8 = TransposeUVWx8_Any_NEON;
+    if (IS_ALIGNED(width, 8)) {
+      TransposeUVWx8 = TransposeUVWx8_NEON;
+    }
+  }
+#endif
+#if defined(HAS_TRANSPOSEUVWXH_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    TransposeUVWxH = TransposeUVWxH_SME;
   }
 #endif
 #if defined(HAS_TRANSPOSEUVWX8_SSE2)
@@ -292,6 +340,13 @@
 #endif
 #endif /* defined(HAS_TRANSPOSEUVWX16_MSA) */
 
+#if defined(HAS_TRANSPOSEUVWXH_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    TransposeUVWxH(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
+                   width, i);
+    return;
+  }
+#endif
 #if defined(HAS_TRANSPOSEUVWX16_MSA)
   // Work through the source in 8x8 tiles.
   while (i >= 16) {
diff --git a/source/rotate_any.cc b/source/rotate_any.cc
index 88ca787..ac94253 100644
--- a/source/rotate_any.cc
+++ b/source/rotate_any.cc
@@ -18,31 +18,34 @@
 extern "C" {
 #endif
 
-#define TANY(NAMEANY, TPOS_SIMD, MASK)                                        \
-  void NAMEANY(const uint8_t* src, int src_stride, uint8_t* dst,              \
-               int dst_stride, int width) {                                   \
-    int r = width & MASK;                                                     \
-    int n = width - r;                                                        \
-    if (n > 0) {                                                              \
-      TPOS_SIMD(src, src_stride, dst, dst_stride, n);                         \
-    }                                                                         \
-    TransposeWx8_C(src + n, src_stride, dst + n * dst_stride, dst_stride, r); \
+#define TANY(NAMEANY, TPOS_SIMD, TPOS_C, MASK)                        \
+  void NAMEANY(const uint8_t* src, int src_stride, uint8_t* dst,      \
+               int dst_stride, int width) {                           \
+    int r = width & MASK;                                             \
+    int n = width - r;                                                \
+    if (n > 0) {                                                      \
+      TPOS_SIMD(src, src_stride, dst, dst_stride, n);                 \
+    }                                                                 \
+    TPOS_C(src + n, src_stride, dst + n * dst_stride, dst_stride, r); \
   }
 
 #ifdef HAS_TRANSPOSEWX8_NEON
-TANY(TransposeWx8_Any_NEON, TransposeWx8_NEON, 7)
+TANY(TransposeWx8_Any_NEON, TransposeWx8_NEON, TransposeWx8_C, 7)
+#endif
+#ifdef HAS_TRANSPOSEWX16_NEON
+TANY(TransposeWx16_Any_NEON, TransposeWx16_NEON, TransposeWx16_C, 15)
 #endif
 #ifdef HAS_TRANSPOSEWX8_SSSE3
-TANY(TransposeWx8_Any_SSSE3, TransposeWx8_SSSE3, 7)
+TANY(TransposeWx8_Any_SSSE3, TransposeWx8_SSSE3, TransposeWx8_C, 7)
 #endif
 #ifdef HAS_TRANSPOSEWX8_FAST_SSSE3
-TANY(TransposeWx8_Fast_Any_SSSE3, TransposeWx8_Fast_SSSE3, 15)
+TANY(TransposeWx8_Fast_Any_SSSE3, TransposeWx8_Fast_SSSE3, TransposeWx8_C, 15)
 #endif
 #ifdef HAS_TRANSPOSEWX16_MSA
-TANY(TransposeWx16_Any_MSA, TransposeWx16_MSA, 15)
+TANY(TransposeWx16_Any_MSA, TransposeWx16_MSA, TransposeWx16_C, 15)
 #endif
 #ifdef HAS_TRANSPOSEWX16_LSX
-TANY(TransposeWx16_Any_LSX, TransposeWx16_LSX, 15)
+TANY(TransposeWx16_Any_LSX, TransposeWx16_LSX, TransposeWx16_C, 15)
 #endif
 #undef TANY
 
diff --git a/source/rotate_argb.cc b/source/rotate_argb.cc
index d55fac4..7fda09d 100644
--- a/source/rotate_argb.cc
+++ b/source/rotate_argb.cc
@@ -189,6 +189,12 @@
     CopyRow = IS_ALIGNED(width * 4, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
   }
 #endif
+#if defined(HAS_COPYROW_AVX512BW)
+  if (TestCpuFlag(kCpuHasAVX512BW)) {
+    CopyRow =
+        IS_ALIGNED(width * 4, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW;
+  }
+#endif
 #if defined(HAS_COPYROW_ERMS)
   if (TestCpuFlag(kCpuHasERMS)) {
     CopyRow = CopyRow_ERMS;
@@ -199,6 +205,11 @@
     CopyRow = IS_ALIGNED(width * 4, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
   }
 #endif
+#if defined(HAS_COPYROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    CopyRow = CopyRow_SME;
+  }
+#endif
 #if defined(HAS_COPYROW_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     CopyRow = CopyRow_RVV;
diff --git a/source/rotate_common.cc b/source/rotate_common.cc
index e72608e..e0341fe 100644
--- a/source/rotate_common.cc
+++ b/source/rotate_common.cc
@@ -36,6 +36,16 @@
   }
 }
 
+void TransposeWx16_C(const uint8_t* src,
+                     int src_stride,
+                     uint8_t* dst,
+                     int dst_stride,
+                     int width) {
+  TransposeWx8_C(src, src_stride, dst, dst_stride, width);
+  TransposeWx8_C((src + 8 * src_stride), src_stride, (dst + 8), dst_stride,
+                 width);
+}
+
 void TransposeUVWx8_C(const uint8_t* src,
                       int src_stride,
                       uint8_t* dst_a,
diff --git a/source/rotate_gcc.cc b/source/rotate_gcc.cc
index fd5eee0..ae7436b 100644
--- a/source/rotate_gcc.cc
+++ b/source/rotate_gcc.cc
@@ -17,7 +17,9 @@
 #endif
 
 // This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 
 // Transpose 8x8. 32 or 64 bit, but not NaCL for 64 bit.
 #if defined(HAS_TRANSPOSEWX8_SSSE3)
@@ -30,7 +32,7 @@
       // Read in the data from the source pointer.
       // First round of bit swap.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"
       "movq        (%0,%3),%%xmm1                \n"
       "lea         (%0,%3,2),%0                  \n"
@@ -120,7 +122,7 @@
       // Read in the data from the source pointer.
       // First round of bit swap.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      (%0,%3),%%xmm1                \n"
       "lea         (%0,%3,2),%0                  \n"
@@ -265,7 +267,7 @@
       // Read in the data from the source pointer.
       // First round of bit swap.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      (%0,%4),%%xmm1                \n"
       "lea         (%0,%4,2),%0                  \n"
@@ -393,7 +395,7 @@
                           int width) {
   asm volatile(
       // Main loop transpose 4x4.  Read a column, write a row.
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // a b c d
       "movdqu      (%0,%3),%%xmm1                \n"  // e f g h
       "lea         (%0,%3,2),%0                  \n"  // src += stride * 2
@@ -449,7 +451,7 @@
                           int width) {
   asm volatile(
       // Main loop transpose 2 blocks of 4x4.  Read a column, write a row.
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"  // a b c d
       "vmovdqu     (%0,%3),%%xmm1                \n"  // e f g h
       "lea         (%0,%3,2),%0                  \n"  // src += stride * 2
@@ -484,7 +486,7 @@
       "sub         %4,%1                         \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),                     // %0
         "+r"(dst),                     // %1
         "+rm"(width)                   // %2
diff --git a/source/rotate_lsx.cc b/source/rotate_lsx.cc
index 94a2b91..b292803 100644
--- a/source/rotate_lsx.cc
+++ b/source/rotate_lsx.cc
@@ -61,16 +61,6 @@
     _dst += _stride2;                                   \
   }
 
-void TransposeWx16_C(const uint8_t* src,
-                     int src_stride,
-                     uint8_t* dst,
-                     int dst_stride,
-                     int width) {
-  TransposeWx8_C(src, src_stride, dst, dst_stride, width);
-  TransposeWx8_C((src + 8 * src_stride), src_stride, (dst + 8), dst_stride,
-                 width);
-}
-
 void TransposeUVWx16_C(const uint8_t* src,
                        int src_stride,
                        uint8_t* dst_a,
diff --git a/source/rotate_msa.cc b/source/rotate_msa.cc
index 99bdca6..d4e62b1 100644
--- a/source/rotate_msa.cc
+++ b/source/rotate_msa.cc
@@ -51,16 +51,6 @@
     out3 = (v16u8)__msa_ilvl_d((v2i64)in3, (v2i64)in2);     \
   }
 
-void TransposeWx16_C(const uint8_t* src,
-                     int src_stride,
-                     uint8_t* dst,
-                     int dst_stride,
-                     int width) {
-  TransposeWx8_C(src, src_stride, dst, dst_stride, width);
-  TransposeWx8_C((src + 8 * src_stride), src_stride, (dst + 8), dst_stride,
-                 width);
-}
-
 void TransposeUVWx16_C(const uint8_t* src,
                        int src_stride,
                        uint8_t* dst_a,
diff --git a/source/rotate_neon.cc b/source/rotate_neon.cc
index 569a731..27bd225 100644
--- a/source/rotate_neon.cc
+++ b/source/rotate_neon.cc
@@ -21,38 +21,35 @@
 #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \
     !defined(__aarch64__)
 
-static const uvec8 kVTbl4x4Transpose = {0, 4, 8,  12, 1, 5, 9,  13,
-                                        2, 6, 10, 14, 3, 7, 11, 15};
-
 void TransposeWx8_NEON(const uint8_t* src,
                        int src_stride,
                        uint8_t* dst,
                        int dst_stride,
                        int width) {
-  const uint8_t* src_temp;
+  const uint8_t* temp;
   asm volatile(
       // loops are on blocks of 8. loop will stop when
       // counter gets to or below 0. starting the counter
       // at w-8 allow for this
-      "sub         %5, #8                        \n"
+      "sub         %[width], #8                  \n"
 
-      // handle 8x8 blocks. this should be the majority of the plane
-      "1:                                        \n"
-      "mov         %0, %1                        \n"
-
-      "vld1.8      {d0}, [%0], %2                \n"
-      "vld1.8      {d1}, [%0], %2                \n"
-      "vld1.8      {d2}, [%0], %2                \n"
-      "vld1.8      {d3}, [%0], %2                \n"
-      "vld1.8      {d4}, [%0], %2                \n"
-      "vld1.8      {d5}, [%0], %2                \n"
-      "vld1.8      {d6}, [%0], %2                \n"
-      "vld1.8      {d7}, [%0]                    \n"
+      "1:          \n"
+      "mov         %[temp], %[src]               \n"
+      "vld1.8      {d0}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d1}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d2}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d3}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d4}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d5}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d6}, [%[temp]], %[src_stride] \n"
+      "vld1.8      {d7}, [%[temp]]               \n"
+      "add         %[src], #8                    \n"
 
       "vtrn.8      d1, d0                        \n"
       "vtrn.8      d3, d2                        \n"
       "vtrn.8      d5, d4                        \n"
       "vtrn.8      d7, d6                        \n"
+      "subs        %[width], #8                  \n"
 
       "vtrn.16     d1, d3                        \n"
       "vtrn.16     d0, d2                        \n"
@@ -69,129 +66,27 @@
       "vrev16.8    q2, q2                        \n"
       "vrev16.8    q3, q3                        \n"
 
-      "mov         %0, %3                        \n"
+      "mov         %[temp], %[dst]               \n"
+      "vst1.8      {d1}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d0}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d3}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d2}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d5}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d4}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d7}, [%[temp]], %[dst_stride] \n"
+      "vst1.8      {d6}, [%[temp]]               \n"
+      "add         %[dst], %[dst], %[dst_stride], lsl #3 \n"
 
-      "vst1.8      {d1}, [%0], %4                \n"
-      "vst1.8      {d0}, [%0], %4                \n"
-      "vst1.8      {d3}, [%0], %4                \n"
-      "vst1.8      {d2}, [%0], %4                \n"
-      "vst1.8      {d5}, [%0], %4                \n"
-      "vst1.8      {d4}, [%0], %4                \n"
-      "vst1.8      {d7}, [%0], %4                \n"
-      "vst1.8      {d6}, [%0]                    \n"
-
-      "add         %1, #8                        \n"  // src += 8
-      "add         %3, %3, %4, lsl #3            \n"  // dst += 8 * dst_stride
-      "subs        %5,  #8                       \n"  // w   -= 8
       "bge         1b                            \n"
-
-      // add 8 back to counter. if the result is 0 there are
-      // no residuals.
-      "adds        %5, #8                        \n"
-      "beq         4f                            \n"
-
-      // some residual, so between 1 and 7 lines left to transpose
-      "cmp         %5, #2                        \n"
-      "blt         3f                            \n"
-
-      "cmp         %5, #4                        \n"
-      "blt         2f                            \n"
-
-      // 4x8 block
-      "mov         %0, %1                        \n"
-      "vld1.32     {d0[0]}, [%0], %2             \n"
-      "vld1.32     {d0[1]}, [%0], %2             \n"
-      "vld1.32     {d1[0]}, [%0], %2             \n"
-      "vld1.32     {d1[1]}, [%0], %2             \n"
-      "vld1.32     {d2[0]}, [%0], %2             \n"
-      "vld1.32     {d2[1]}, [%0], %2             \n"
-      "vld1.32     {d3[0]}, [%0], %2             \n"
-      "vld1.32     {d3[1]}, [%0]                 \n"
-
-      "mov         %0, %3                        \n"
-
-      "vld1.8      {q3}, [%6]                    \n"
-
-      "vtbl.8      d4, {d0, d1}, d6              \n"
-      "vtbl.8      d5, {d0, d1}, d7              \n"
-      "vtbl.8      d0, {d2, d3}, d6              \n"
-      "vtbl.8      d1, {d2, d3}, d7              \n"
-
-      // TODO(frkoenig): Rework shuffle above to
-      // write out with 4 instead of 8 writes.
-      "vst1.32     {d4[0]}, [%0], %4             \n"
-      "vst1.32     {d4[1]}, [%0], %4             \n"
-      "vst1.32     {d5[0]}, [%0], %4             \n"
-      "vst1.32     {d5[1]}, [%0]                 \n"
-
-      "add         %0, %3, #4                    \n"
-      "vst1.32     {d0[0]}, [%0], %4             \n"
-      "vst1.32     {d0[1]}, [%0], %4             \n"
-      "vst1.32     {d1[0]}, [%0], %4             \n"
-      "vst1.32     {d1[1]}, [%0]                 \n"
-
-      "add         %1, #4                        \n"  // src += 4
-      "add         %3, %3, %4, lsl #2            \n"  // dst += 4 * dst_stride
-      "subs        %5,  #4                       \n"  // w   -= 4
-      "beq         4f                            \n"
-
-      // some residual, check to see if it includes a 2x8 block,
-      // or less
-      "cmp         %5, #2                        \n"
-      "blt         3f                            \n"
-
-      // 2x8 block
-      "2:                                        \n"
-      "mov         %0, %1                        \n"
-      "vld1.16     {d0[0]}, [%0], %2             \n"
-      "vld1.16     {d1[0]}, [%0], %2             \n"
-      "vld1.16     {d0[1]}, [%0], %2             \n"
-      "vld1.16     {d1[1]}, [%0], %2             \n"
-      "vld1.16     {d0[2]}, [%0], %2             \n"
-      "vld1.16     {d1[2]}, [%0], %2             \n"
-      "vld1.16     {d0[3]}, [%0], %2             \n"
-      "vld1.16     {d1[3]}, [%0]                 \n"
-
-      "vtrn.8      d0, d1                        \n"
-
-      "mov         %0, %3                        \n"
-
-      "vst1.64     {d0}, [%0], %4                \n"
-      "vst1.64     {d1}, [%0]                    \n"
-
-      "add         %1, #2                        \n"  // src += 2
-      "add         %3, %3, %4, lsl #1            \n"  // dst += 2 * dst_stride
-      "subs        %5,  #2                       \n"  // w   -= 2
-      "beq         4f                            \n"
-
-      // 1x8 block
-      "3:                                        \n"
-      "vld1.8      {d0[0]}, [%1], %2             \n"
-      "vld1.8      {d0[1]}, [%1], %2             \n"
-      "vld1.8      {d0[2]}, [%1], %2             \n"
-      "vld1.8      {d0[3]}, [%1], %2             \n"
-      "vld1.8      {d0[4]}, [%1], %2             \n"
-      "vld1.8      {d0[5]}, [%1], %2             \n"
-      "vld1.8      {d0[6]}, [%1], %2             \n"
-      "vld1.8      {d0[7]}, [%1]                 \n"
-
-      "vst1.64     {d0}, [%3]                    \n"
-
-      "4:                                        \n"
-
-      : "=&r"(src_temp),         // %0
-        "+r"(src),               // %1
-        "+r"(src_stride),        // %2
-        "+r"(dst),               // %3
-        "+r"(dst_stride),        // %4
-        "+r"(width)              // %5
-      : "r"(&kVTbl4x4Transpose)  // %6
+      : [temp] "=&r"(temp),            // %[temp]
+        [src] "+r"(src),               // %[src]
+        [dst] "+r"(dst),               // %[dst]
+        [width] "+r"(width)            // %[width]
+      : [src_stride] "r"(src_stride),  // %[src_stride]
+        [dst_stride] "r"(dst_stride)   // %[dst_stride]
       : "memory", "cc", "q0", "q1", "q2", "q3");
 }
 
-static const uvec8 kVTbl4x4TransposeDi = {0, 8,  1, 9,  2, 10, 3, 11,
-                                          4, 12, 5, 13, 6, 14, 7, 15};
-
 void TransposeUVWx8_NEON(const uint8_t* src,
                          int src_stride,
                          uint8_t* dst_a,
@@ -199,30 +94,30 @@
                          uint8_t* dst_b,
                          int dst_stride_b,
                          int width) {
-  const uint8_t* src_temp;
+  const uint8_t* temp;
   asm volatile(
       // loops are on blocks of 8. loop will stop when
       // counter gets to or below 0. starting the counter
       // at w-8 allow for this
-      "sub         %7, #8                        \n"
+      "sub         %[width], #8                  \n"
 
-      // handle 8x8 blocks. this should be the majority of the plane
-      "1:                                        \n"
-      "mov         %0, %1                        \n"
-
-      "vld2.8      {d0,  d1},  [%0], %2          \n"
-      "vld2.8      {d2,  d3},  [%0], %2          \n"
-      "vld2.8      {d4,  d5},  [%0], %2          \n"
-      "vld2.8      {d6,  d7},  [%0], %2          \n"
-      "vld2.8      {d16, d17}, [%0], %2          \n"
-      "vld2.8      {d18, d19}, [%0], %2          \n"
-      "vld2.8      {d20, d21}, [%0], %2          \n"
-      "vld2.8      {d22, d23}, [%0]              \n"
+      "1:          \n"
+      "mov         %[temp], %[src]               \n"
+      "vld2.8      {d0,  d1},  [%[temp]], %[src_stride] \n"
+      "vld2.8      {d2,  d3},  [%[temp]], %[src_stride] \n"
+      "vld2.8      {d4,  d5},  [%[temp]], %[src_stride] \n"
+      "vld2.8      {d6,  d7},  [%[temp]], %[src_stride] \n"
+      "vld2.8      {d16, d17}, [%[temp]], %[src_stride] \n"
+      "vld2.8      {d18, d19}, [%[temp]], %[src_stride] \n"
+      "vld2.8      {d20, d21}, [%[temp]], %[src_stride] \n"
+      "vld2.8      {d22, d23}, [%[temp]]         \n"
+      "add         %[src], #8*2                  \n"
 
       "vtrn.8      q1, q0                        \n"
       "vtrn.8      q3, q2                        \n"
       "vtrn.8      q9, q8                        \n"
       "vtrn.8      q11, q10                      \n"
+      "subs        %[width], #8                  \n"
 
       "vtrn.16     q1, q3                        \n"
       "vtrn.16     q0, q2                        \n"
@@ -243,171 +138,37 @@
       "vrev16.8    q10, q10                      \n"
       "vrev16.8    q11, q11                      \n"
 
-      "mov         %0, %3                        \n"
+      "mov         %[temp], %[dst_a]             \n"
+      "vst1.8      {d2},  [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d0},  [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d6},  [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d4},  [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d18}, [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d16}, [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d22}, [%[temp]], %[dst_stride_a] \n"
+      "vst1.8      {d20}, [%[temp]]              \n"
+      "add         %[dst_a], %[dst_a], %[dst_stride_a], lsl #3 \n"
 
-      "vst1.8      {d2},  [%0], %4               \n"
-      "vst1.8      {d0},  [%0], %4               \n"
-      "vst1.8      {d6},  [%0], %4               \n"
-      "vst1.8      {d4},  [%0], %4               \n"
-      "vst1.8      {d18}, [%0], %4               \n"
-      "vst1.8      {d16}, [%0], %4               \n"
-      "vst1.8      {d22}, [%0], %4               \n"
-      "vst1.8      {d20}, [%0]                   \n"
+      "mov         %[temp], %[dst_b]             \n"
+      "vst1.8      {d3},  [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d1},  [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d7},  [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d5},  [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d19}, [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d17}, [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d23}, [%[temp]], %[dst_stride_b] \n"
+      "vst1.8      {d21}, [%[temp]]              \n"
+      "add         %[dst_b], %[dst_b], %[dst_stride_b], lsl #3 \n"
 
-      "mov         %0, %5                        \n"
-
-      "vst1.8      {d3},  [%0], %6               \n"
-      "vst1.8      {d1},  [%0], %6               \n"
-      "vst1.8      {d7},  [%0], %6               \n"
-      "vst1.8      {d5},  [%0], %6               \n"
-      "vst1.8      {d19}, [%0], %6               \n"
-      "vst1.8      {d17}, [%0], %6               \n"
-      "vst1.8      {d23}, [%0], %6               \n"
-      "vst1.8      {d21}, [%0]                   \n"
-
-      "add         %1, #8*2                      \n"  // src   += 8*2
-      "add         %3, %3, %4, lsl #3            \n"  // dst_a += 8 *
-                                                      // dst_stride_a
-      "add         %5, %5, %6, lsl #3            \n"  // dst_b += 8 *
-                                                      // dst_stride_b
-      "subs        %7,  #8                       \n"  // w     -= 8
       "bge         1b                            \n"
-
-      // add 8 back to counter. if the result is 0 there are
-      // no residuals.
-      "adds        %7, #8                        \n"
-      "beq         4f                            \n"
-
-      // some residual, so between 1 and 7 lines left to transpose
-      "cmp         %7, #2                        \n"
-      "blt         3f                            \n"
-
-      "cmp         %7, #4                        \n"
-      "blt         2f                            \n"
-
-      // TODO(frkoenig): Clean this up
-      // 4x8 block
-      "mov         %0, %1                        \n"
-      "vld1.64     {d0}, [%0], %2                \n"
-      "vld1.64     {d1}, [%0], %2                \n"
-      "vld1.64     {d2}, [%0], %2                \n"
-      "vld1.64     {d3}, [%0], %2                \n"
-      "vld1.64     {d4}, [%0], %2                \n"
-      "vld1.64     {d5}, [%0], %2                \n"
-      "vld1.64     {d6}, [%0], %2                \n"
-      "vld1.64     {d7}, [%0]                    \n"
-
-      "vld1.8      {q15}, [%8]                   \n"
-
-      "vtrn.8      q0, q1                        \n"
-      "vtrn.8      q2, q3                        \n"
-
-      "vtbl.8      d16, {d0, d1}, d30            \n"
-      "vtbl.8      d17, {d0, d1}, d31            \n"
-      "vtbl.8      d18, {d2, d3}, d30            \n"
-      "vtbl.8      d19, {d2, d3}, d31            \n"
-      "vtbl.8      d20, {d4, d5}, d30            \n"
-      "vtbl.8      d21, {d4, d5}, d31            \n"
-      "vtbl.8      d22, {d6, d7}, d30            \n"
-      "vtbl.8      d23, {d6, d7}, d31            \n"
-
-      "mov         %0, %3                        \n"
-
-      "vst1.32     {d16[0]},  [%0], %4           \n"
-      "vst1.32     {d16[1]},  [%0], %4           \n"
-      "vst1.32     {d17[0]},  [%0], %4           \n"
-      "vst1.32     {d17[1]},  [%0], %4           \n"
-
-      "add         %0, %3, #4                    \n"
-      "vst1.32     {d20[0]}, [%0], %4            \n"
-      "vst1.32     {d20[1]}, [%0], %4            \n"
-      "vst1.32     {d21[0]}, [%0], %4            \n"
-      "vst1.32     {d21[1]}, [%0]                \n"
-
-      "mov         %0, %5                        \n"
-
-      "vst1.32     {d18[0]}, [%0], %6            \n"
-      "vst1.32     {d18[1]}, [%0], %6            \n"
-      "vst1.32     {d19[0]}, [%0], %6            \n"
-      "vst1.32     {d19[1]}, [%0], %6            \n"
-
-      "add         %0, %5, #4                    \n"
-      "vst1.32     {d22[0]},  [%0], %6           \n"
-      "vst1.32     {d22[1]},  [%0], %6           \n"
-      "vst1.32     {d23[0]},  [%0], %6           \n"
-      "vst1.32     {d23[1]},  [%0]               \n"
-
-      "add         %1, #4*2                      \n"  // src   += 4 * 2
-      "add         %3, %3, %4, lsl #2            \n"  // dst_a += 4 *
-                                                      // dst_stride_a
-      "add         %5, %5, %6, lsl #2            \n"  // dst_b += 4 *
-                                                      // dst_stride_b
-      "subs        %7,  #4                       \n"  // w     -= 4
-      "beq         4f                            \n"
-
-      // some residual, check to see if it includes a 2x8 block,
-      // or less
-      "cmp         %7, #2                        \n"
-      "blt         3f                            \n"
-
-      // 2x8 block
-      "2:                                        \n"
-      "mov         %0, %1                        \n"
-      "vld2.16     {d0[0], d2[0]}, [%0], %2      \n"
-      "vld2.16     {d1[0], d3[0]}, [%0], %2      \n"
-      "vld2.16     {d0[1], d2[1]}, [%0], %2      \n"
-      "vld2.16     {d1[1], d3[1]}, [%0], %2      \n"
-      "vld2.16     {d0[2], d2[2]}, [%0], %2      \n"
-      "vld2.16     {d1[2], d3[2]}, [%0], %2      \n"
-      "vld2.16     {d0[3], d2[3]}, [%0], %2      \n"
-      "vld2.16     {d1[3], d3[3]}, [%0]          \n"
-
-      "vtrn.8      d0, d1                        \n"
-      "vtrn.8      d2, d3                        \n"
-
-      "mov         %0, %3                        \n"
-
-      "vst1.64     {d0}, [%0], %4                \n"
-      "vst1.64     {d2}, [%0]                    \n"
-
-      "mov         %0, %5                        \n"
-
-      "vst1.64     {d1}, [%0], %6                \n"
-      "vst1.64     {d3}, [%0]                    \n"
-
-      "add         %1, #2*2                      \n"  // src   += 2 * 2
-      "add         %3, %3, %4, lsl #1            \n"  // dst_a += 2 *
-                                                      // dst_stride_a
-      "add         %5, %5, %6, lsl #1            \n"  // dst_b += 2 *
-                                                      // dst_stride_b
-      "subs        %7,  #2                       \n"  // w     -= 2
-      "beq         4f                            \n"
-
-      // 1x8 block
-      "3:                                        \n"
-      "vld2.8      {d0[0], d1[0]}, [%1], %2      \n"
-      "vld2.8      {d0[1], d1[1]}, [%1], %2      \n"
-      "vld2.8      {d0[2], d1[2]}, [%1], %2      \n"
-      "vld2.8      {d0[3], d1[3]}, [%1], %2      \n"
-      "vld2.8      {d0[4], d1[4]}, [%1], %2      \n"
-      "vld2.8      {d0[5], d1[5]}, [%1], %2      \n"
-      "vld2.8      {d0[6], d1[6]}, [%1], %2      \n"
-      "vld2.8      {d0[7], d1[7]}, [%1]          \n"
-
-      "vst1.64     {d0}, [%3]                    \n"
-      "vst1.64     {d1}, [%5]                    \n"
-
-      "4:                                        \n"
-
-      : "=&r"(src_temp),           // %0
-        "+r"(src),                 // %1
-        "+r"(src_stride),          // %2
-        "+r"(dst_a),               // %3
-        "+r"(dst_stride_a),        // %4
-        "+r"(dst_b),               // %5
-        "+r"(dst_stride_b),        // %6
-        "+r"(width)                // %7
-      : "r"(&kVTbl4x4TransposeDi)  // %8
+      : [temp] "=&r"(temp),                // %[temp]
+        [src] "+r"(src),                   // %[src]
+        [dst_a] "+r"(dst_a),               // %[dst_a]
+        [dst_b] "+r"(dst_b),               // %[dst_b]
+        [width] "+r"(width)                // %[width]
+      : [src_stride] "r"(src_stride),      // %[src_stride]
+        [dst_stride_a] "r"(dst_stride_a),  // %[dst_stride_a]
+        [dst_stride_b] "r"(dst_stride_b)   // %[dst_stride_b]
       : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11");
 }
 
@@ -425,7 +186,7 @@
   uint8_t* dst3 = dst2 + dst_stride;
   asm volatile(
       // Main loop transpose 4x4.  Read a column, write a row.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.32     {d0[0], d2[0], d4[0], d6[0]}, [%0], %9 \n"
       "vld4.32     {d0[1], d2[1], d4[1], d6[1]}, [%1], %9 \n"
       "vld4.32     {d1[0], d3[0], d5[0], d7[0]}, [%2], %9 \n"
diff --git a/source/rotate_neon64.cc b/source/rotate_neon64.cc
index 95047fa..e09bcb1 100644
--- a/source/rotate_neon64.cc
+++ b/source/rotate_neon64.cc
@@ -21,201 +21,122 @@
 // This module is for GCC Neon armv8 64 bit.
 #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
 
-static const uvec8 kVTbl4x4Transpose = {0, 4, 8,  12, 1, 5, 9,  13,
-                                        2, 6, 10, 14, 3, 7, 11, 15};
-
-void TransposeWx8_NEON(const uint8_t* src,
-                       int src_stride,
-                       uint8_t* dst,
-                       int dst_stride,
-                       int width) {
+void TransposeWx16_NEON(const uint8_t* src,
+                        int src_stride,
+                        uint8_t* dst,
+                        int dst_stride,
+                        int width) {
   const uint8_t* src_temp;
   asm volatile(
-      // loops are on blocks of 8. loop will stop when
-      // counter gets to or below 0. starting the counter
-      // at w-8 allow for this
-      "sub         %w3, %w3, #8                  \n"
+      "1:          \n"
+      "mov         %[src_temp], %[src]           \n"
 
-      // handle 8x8 blocks. this should be the majority of the plane
-      "1:                                        \n"
-      "mov         %0, %1                        \n"
+      "ld1         {v16.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v17.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v18.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v19.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v20.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v21.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v22.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v23.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v24.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v25.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v26.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v27.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v28.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v29.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v30.16b}, [%[src_temp]], %[src_stride] \n"
+      "ld1         {v31.16b}, [%[src_temp]], %[src_stride] \n"
 
-      "ld1         {v0.8b}, [%0], %5             \n"
-      "ld1         {v1.8b}, [%0], %5             \n"
-      "ld1         {v2.8b}, [%0], %5             \n"
-      "ld1         {v3.8b}, [%0], %5             \n"
-      "ld1         {v4.8b}, [%0], %5             \n"
-      "ld1         {v5.8b}, [%0], %5             \n"
-      "ld1         {v6.8b}, [%0], %5             \n"
-      "ld1         {v7.8b}, [%0]                 \n"
-      "mov         %0, %1                        \n"
+      "add         %[src], %[src], #16           \n"
 
-      "trn2        v16.8b, v0.8b, v1.8b          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "trn1        v17.8b, v0.8b, v1.8b          \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v18.8b, v2.8b, v3.8b          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 1
-      "trn1        v19.8b, v2.8b, v3.8b          \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v20.8b, v4.8b, v5.8b          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 2
-      "trn1        v21.8b, v4.8b, v5.8b          \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v22.8b, v6.8b, v7.8b          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 3
-      "trn1        v23.8b, v6.8b, v7.8b          \n"
-      "add         %0, %0, %5                    \n"
+      // Transpose bytes within each 2x2 block.
+      "trn1        v0.16b, v16.16b, v17.16b      \n"
+      "trn2        v1.16b, v16.16b, v17.16b      \n"
+      "trn1        v2.16b, v18.16b, v19.16b      \n"
+      "trn2        v3.16b, v18.16b, v19.16b      \n"
+      "trn1        v4.16b, v20.16b, v21.16b      \n"
+      "trn2        v5.16b, v20.16b, v21.16b      \n"
+      "trn1        v6.16b, v22.16b, v23.16b      \n"
+      "trn2        v7.16b, v22.16b, v23.16b      \n"
+      "trn1        v8.16b, v24.16b, v25.16b      \n"
+      "trn2        v9.16b, v24.16b, v25.16b      \n"
+      "trn1        v10.16b, v26.16b, v27.16b     \n"
+      "trn2        v11.16b, v26.16b, v27.16b     \n"
+      "trn1        v12.16b, v28.16b, v29.16b     \n"
+      "trn2        v13.16b, v28.16b, v29.16b     \n"
+      "trn1        v14.16b, v30.16b, v31.16b     \n"
+      "trn2        v15.16b, v30.16b, v31.16b     \n"
 
-      "trn2        v3.4h, v17.4h, v19.4h         \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 4
-      "trn1        v1.4h, v17.4h, v19.4h         \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v2.4h, v16.4h, v18.4h         \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 5
-      "trn1        v0.4h, v16.4h, v18.4h         \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v7.4h, v21.4h, v23.4h         \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 6
-      "trn1        v5.4h, v21.4h, v23.4h         \n"
-      "add         %0, %0, %5                    \n"
-      "trn2        v6.4h, v20.4h, v22.4h         \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // row 7
-      "trn1        v4.4h, v20.4h, v22.4h         \n"
+      // Transpose 2x2-byte blocks within each 4x4 block.
+      "trn1        v16.8h, v0.8h, v2.8h          \n"
+      "trn1        v17.8h, v1.8h, v3.8h          \n"
+      "trn2        v18.8h, v0.8h, v2.8h          \n"
+      "trn2        v19.8h, v1.8h, v3.8h          \n"
+      "trn1        v20.8h, v4.8h, v6.8h          \n"
+      "trn1        v21.8h, v5.8h, v7.8h          \n"
+      "trn2        v22.8h, v4.8h, v6.8h          \n"
+      "trn2        v23.8h, v5.8h, v7.8h          \n"
+      "trn1        v24.8h, v8.8h, v10.8h         \n"
+      "trn1        v25.8h, v9.8h, v11.8h         \n"
+      "trn2        v26.8h, v8.8h, v10.8h         \n"
+      "trn2        v27.8h, v9.8h, v11.8h         \n"
+      "trn1        v28.8h, v12.8h, v14.8h        \n"
+      "trn1        v29.8h, v13.8h, v15.8h        \n"
+      "trn2        v30.8h, v12.8h, v14.8h        \n"
+      "trn2        v31.8h, v13.8h, v15.8h        \n"
 
-      "trn2        v21.2s, v1.2s, v5.2s          \n"
-      "trn1        v17.2s, v1.2s, v5.2s          \n"
-      "trn2        v20.2s, v0.2s, v4.2s          \n"
-      "trn1        v16.2s, v0.2s, v4.2s          \n"
-      "trn2        v23.2s, v3.2s, v7.2s          \n"
-      "trn1        v19.2s, v3.2s, v7.2s          \n"
-      "trn2        v22.2s, v2.2s, v6.2s          \n"
-      "trn1        v18.2s, v2.2s, v6.2s          \n"
+      "subs        %w[width], %w[width], #16     \n"
 
-      "mov         %0, %2                        \n"
+      // Transpose 4x4-byte blocks within each 8x8 block.
+      "trn1        v0.4s, v16.4s, v20.4s         \n"
+      "trn1        v2.4s, v17.4s, v21.4s         \n"
+      "trn1        v4.4s, v18.4s, v22.4s         \n"
+      "trn1        v6.4s, v19.4s, v23.4s         \n"
+      "trn2        v8.4s, v16.4s, v20.4s         \n"
+      "trn2        v10.4s, v17.4s, v21.4s        \n"
+      "trn2        v12.4s, v18.4s, v22.4s        \n"
+      "trn2        v14.4s, v19.4s, v23.4s        \n"
+      "trn1        v1.4s, v24.4s, v28.4s         \n"
+      "trn1        v3.4s, v25.4s, v29.4s         \n"
+      "trn1        v5.4s, v26.4s, v30.4s         \n"
+      "trn1        v7.4s, v27.4s, v31.4s         \n"
+      "trn2        v9.4s, v24.4s, v28.4s         \n"
+      "trn2        v11.4s, v25.4s, v29.4s        \n"
+      "trn2        v13.4s, v26.4s, v30.4s        \n"
+      "trn2        v15.4s, v27.4s, v31.4s        \n"
 
-      "st1         {v17.8b}, [%0], %6            \n"
-      "st1         {v16.8b}, [%0], %6            \n"
-      "st1         {v19.8b}, [%0], %6            \n"
-      "st1         {v18.8b}, [%0], %6            \n"
-      "st1         {v21.8b}, [%0], %6            \n"
-      "st1         {v20.8b}, [%0], %6            \n"
-      "st1         {v23.8b}, [%0], %6            \n"
-      "st1         {v22.8b}, [%0]                \n"
+      // Transpose 8x8-byte blocks and store.
+      "st2         {v0.d, v1.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v2.d, v3.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v4.d, v5.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v6.d, v7.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v8.d, v9.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v10.d, v11.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v12.d, v13.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v14.d, v15.d}[0], [%[dst]], %[dst_stride] \n"
+      "st2         {v0.d, v1.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v2.d, v3.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v4.d, v5.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v6.d, v7.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v8.d, v9.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v10.d, v11.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v12.d, v13.d}[1], [%[dst]], %[dst_stride] \n"
+      "st2         {v14.d, v15.d}[1], [%[dst]], %[dst_stride] \n"
 
-      "add         %1, %1, #8                    \n"  // src += 8
-      "add         %2, %2, %6, lsl #3            \n"  // dst += 8 * dst_stride
-      "subs        %w3, %w3, #8                  \n"  // w   -= 8
-      "b.ge        1b                            \n"
-
-      // add 8 back to counter. if the result is 0 there are
-      // no residuals.
-      "adds        %w3, %w3, #8                  \n"
-      "b.eq        4f                            \n"
-
-      // some residual, so between 1 and 7 lines left to transpose
-      "cmp         %w3, #2                       \n"
-      "b.lt        3f                            \n"
-
-      "cmp         %w3, #4                       \n"
-      "b.lt        2f                            \n"
-
-      // 4x8 block
-      "mov         %0, %1                        \n"
-      "ld1         {v0.s}[0], [%0], %5           \n"
-      "ld1         {v0.s}[1], [%0], %5           \n"
-      "ld1         {v0.s}[2], [%0], %5           \n"
-      "ld1         {v0.s}[3], [%0], %5           \n"
-      "ld1         {v1.s}[0], [%0], %5           \n"
-      "ld1         {v1.s}[1], [%0], %5           \n"
-      "ld1         {v1.s}[2], [%0], %5           \n"
-      "ld1         {v1.s}[3], [%0]               \n"
-
-      "mov         %0, %2                        \n"
-
-      "ld1         {v2.16b}, [%4]                \n"
-
-      "tbl         v3.16b, {v0.16b}, v2.16b      \n"
-      "tbl         v0.16b, {v1.16b}, v2.16b      \n"
-
-      // TODO(frkoenig): Rework shuffle above to
-      // write out with 4 instead of 8 writes.
-      "st1 {v3.s}[0], [%0], %6                     \n"
-      "st1 {v3.s}[1], [%0], %6                     \n"
-      "st1 {v3.s}[2], [%0], %6                     \n"
-      "st1 {v3.s}[3], [%0]                         \n"
-
-      "add         %0, %2, #4                      \n"
-      "st1 {v0.s}[0], [%0], %6                     \n"
-      "st1 {v0.s}[1], [%0], %6                     \n"
-      "st1 {v0.s}[2], [%0], %6                     \n"
-      "st1 {v0.s}[3], [%0]                         \n"
-
-      "add         %1, %1, #4                      \n"  // src += 4
-      "add         %2, %2, %6, lsl #2              \n"  // dst += 4 * dst_stride
-      "subs        %w3, %w3, #4                    \n"  // w   -= 4
-      "b.eq        4f                              \n"
-
-      // some residual, check to see if it includes a 2x8 block,
-      // or less
-      "cmp         %w3, #2                         \n"
-      "b.lt        3f                              \n"
-
-      // 2x8 block
-      "2:                                          \n"
-      "mov         %0, %1                          \n"
-      "ld1     {v0.h}[0], [%0], %5                 \n"
-      "ld1     {v1.h}[0], [%0], %5                 \n"
-      "ld1     {v0.h}[1], [%0], %5                 \n"
-      "ld1     {v1.h}[1], [%0], %5                 \n"
-      "ld1     {v0.h}[2], [%0], %5                 \n"
-      "ld1     {v1.h}[2], [%0], %5                 \n"
-      "ld1     {v0.h}[3], [%0], %5                 \n"
-      "ld1     {v1.h}[3], [%0]                     \n"
-
-      "trn2    v2.8b, v0.8b, v1.8b                 \n"
-      "trn1    v3.8b, v0.8b, v1.8b                 \n"
-
-      "mov         %0, %2                          \n"
-
-      "st1     {v3.8b}, [%0], %6                   \n"
-      "st1     {v2.8b}, [%0]                       \n"
-
-      "add         %1, %1, #2                      \n"  // src += 2
-      "add         %2, %2, %6, lsl #1              \n"  // dst += 2 * dst_stride
-      "subs        %w3, %w3,  #2                   \n"  // w   -= 2
-      "b.eq        4f                              \n"
-
-      // 1x8 block
-      "3:                                          \n"
-      "ld1         {v0.b}[0], [%1], %5             \n"
-      "ld1         {v0.b}[1], [%1], %5             \n"
-      "ld1         {v0.b}[2], [%1], %5             \n"
-      "ld1         {v0.b}[3], [%1], %5             \n"
-      "ld1         {v0.b}[4], [%1], %5             \n"
-      "ld1         {v0.b}[5], [%1], %5             \n"
-      "ld1         {v0.b}[6], [%1], %5             \n"
-      "ld1         {v0.b}[7], [%1]                 \n"
-
-      "st1         {v0.8b}, [%2]                   \n"
-
-      "4:                                          \n"
-
-      : "=&r"(src_temp),             // %0
-        "+r"(src),                   // %1
-        "+r"(dst),                   // %2
-        "+r"(width)                  // %3
-      : "r"(&kVTbl4x4Transpose),     // %4
-        "r"((ptrdiff_t)src_stride),  // %5
-        "r"((ptrdiff_t)dst_stride)   // %6
-      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
-        "v17", "v18", "v19", "v20", "v21", "v22", "v23");
+      "b.gt        1b                            \n"
+      : [src] "+r"(src),                          // %[src]
+        [src_temp] "=&r"(src_temp),               // %[src_temp]
+        [dst] "+r"(dst),                          // %[dst]
+        [width] "+r"(width)                       // %[width]
+      : [src_stride] "r"((ptrdiff_t)src_stride),  // %[src_stride]
+        [dst_stride] "r"((ptrdiff_t)dst_stride)   // %[dst_stride]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8",
+        "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18",
+        "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28",
+        "v29", "v30", "v31");
 }
 
-static const uint8_t kVTbl4x4TransposeDi[32] = {
-    0, 16, 32, 48, 2, 18, 34, 50, 4, 20, 36, 52, 6, 22, 38, 54,
-    1, 17, 33, 49, 3, 19, 35, 51, 5, 21, 37, 53, 7, 23, 39, 55};
-
 void TransposeUVWx8_NEON(const uint8_t* src,
                          int src_stride,
                          uint8_t* dst_a,
@@ -223,26 +144,24 @@
                          uint8_t* dst_b,
                          int dst_stride_b,
                          int width) {
-  const uint8_t* src_temp;
+  const uint8_t* temp;
   asm volatile(
       // loops are on blocks of 8. loop will stop when
       // counter gets to or below 0. starting the counter
       // at w-8 allow for this
-      "sub         %w4, %w4, #8                  \n"
+      "sub         %w[width], %w[width], #8      \n"
 
-      // handle 8x8 blocks. this should be the majority of the plane
-      "1:                                        \n"
-      "mov         %0, %1                        \n"
-
-      "ld1         {v0.16b}, [%0], %5            \n"
-      "ld1         {v1.16b}, [%0], %5            \n"
-      "ld1         {v2.16b}, [%0], %5            \n"
-      "ld1         {v3.16b}, [%0], %5            \n"
-      "ld1         {v4.16b}, [%0], %5            \n"
-      "ld1         {v5.16b}, [%0], %5            \n"
-      "ld1         {v6.16b}, [%0], %5            \n"
-      "ld1         {v7.16b}, [%0]                \n"
-      "mov         %0, %1                        \n"
+      "1:          \n"
+      "mov         %[temp], %[src]               \n"
+      "ld1         {v0.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v1.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v2.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v3.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v4.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v5.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v6.16b}, [%[temp]], %[src_stride] \n"
+      "ld1         {v7.16b}, [%[temp]]           \n"
+      "add         %[src], %[src], #16           \n"
 
       "trn1        v16.16b, v0.16b, v1.16b       \n"
       "trn2        v17.16b, v0.16b, v1.16b       \n"
@@ -253,6 +172,8 @@
       "trn1        v22.16b, v6.16b, v7.16b       \n"
       "trn2        v23.16b, v6.16b, v7.16b       \n"
 
+      "subs        %w[width], %w[width],  #8     \n"
+
       "trn1        v0.8h, v16.8h, v18.8h         \n"
       "trn2        v1.8h, v16.8h, v18.8h         \n"
       "trn1        v2.8h, v20.8h, v22.8h         \n"
@@ -271,167 +192,37 @@
       "trn1        v22.4s, v5.4s, v7.4s          \n"
       "trn2        v23.4s, v5.4s, v7.4s          \n"
 
-      "mov         %0, %2                        \n"
+      "mov         %[temp], %[dst_a]             \n"
+      "st1         {v16.d}[0], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v18.d}[0], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v17.d}[0], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v19.d}[0], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v16.d}[1], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v18.d}[1], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v17.d}[1], [%[temp]], %[dst_stride_a] \n"
+      "st1         {v19.d}[1], [%[temp]]         \n"
+      "add         %[dst_a], %[dst_a], %[dst_stride_a], lsl #3 \n"
 
-      "st1         {v16.d}[0], [%0], %6          \n"
-      "st1         {v18.d}[0], [%0], %6          \n"
-      "st1         {v17.d}[0], [%0], %6          \n"
-      "st1         {v19.d}[0], [%0], %6          \n"
-      "st1         {v16.d}[1], [%0], %6          \n"
-      "st1         {v18.d}[1], [%0], %6          \n"
-      "st1         {v17.d}[1], [%0], %6          \n"
-      "st1         {v19.d}[1], [%0]              \n"
+      "mov         %[temp], %[dst_b]             \n"
+      "st1         {v20.d}[0], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v22.d}[0], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v21.d}[0], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v23.d}[0], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v20.d}[1], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v22.d}[1], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v21.d}[1], [%[temp]], %[dst_stride_b] \n"
+      "st1         {v23.d}[1], [%[temp]]         \n"
+      "add         %[dst_b], %[dst_b], %[dst_stride_b], lsl #3 \n"
 
-      "mov         %0, %3                        \n"
-
-      "st1         {v20.d}[0], [%0], %7          \n"
-      "st1         {v22.d}[0], [%0], %7          \n"
-      "st1         {v21.d}[0], [%0], %7          \n"
-      "st1         {v23.d}[0], [%0], %7          \n"
-      "st1         {v20.d}[1], [%0], %7          \n"
-      "st1         {v22.d}[1], [%0], %7          \n"
-      "st1         {v21.d}[1], [%0], %7          \n"
-      "st1         {v23.d}[1], [%0]              \n"
-
-      "add         %1, %1, #16                   \n"  // src   += 8*2
-      "add         %2, %2, %6, lsl #3            \n"  // dst_a += 8 *
-                                                      // dst_stride_a
-      "add         %3, %3, %7, lsl #3            \n"  // dst_b += 8 *
-                                                      // dst_stride_b
-      "subs        %w4, %w4,  #8                 \n"  // w     -= 8
       "b.ge        1b                            \n"
-
-      // add 8 back to counter. if the result is 0 there are
-      // no residuals.
-      "adds        %w4, %w4, #8                  \n"
-      "b.eq        4f                            \n"
-
-      // some residual, so between 1 and 7 lines left to transpose
-      "cmp         %w4, #2                       \n"
-      "b.lt        3f                            \n"
-
-      "cmp         %w4, #4                       \n"
-      "b.lt        2f                            \n"
-
-      // TODO(frkoenig): Clean this up
-      // 4x8 block
-      "mov       %0, %1                          \n"
-      "ld1       {v0.8b}, [%0], %5               \n"
-      "ld1       {v1.8b}, [%0], %5               \n"
-      "ld1       {v2.8b}, [%0], %5               \n"
-      "ld1       {v3.8b}, [%0], %5               \n"
-      "ld1       {v4.8b}, [%0], %5               \n"
-      "ld1       {v5.8b}, [%0], %5               \n"
-      "ld1       {v6.8b}, [%0], %5               \n"
-      "ld1       {v7.8b}, [%0]                   \n"
-
-      "ld1       {v30.16b}, [%8], #16            \n"
-      "ld1       {v31.16b}, [%8]                 \n"
-
-      "tbl       v16.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v30.16b  \n"
-      "tbl       v17.16b, {v0.16b, v1.16b, v2.16b, v3.16b}, v31.16b  \n"
-      "tbl       v18.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v30.16b  \n"
-      "tbl       v19.16b, {v4.16b, v5.16b, v6.16b, v7.16b}, v31.16b  \n"
-
-      "mov       %0, %2                          \n"
-
-      "st1       {v16.s}[0],  [%0], %6           \n"
-      "st1       {v16.s}[1],  [%0], %6           \n"
-      "st1       {v16.s}[2],  [%0], %6           \n"
-      "st1       {v16.s}[3],  [%0], %6           \n"
-
-      "add       %0, %2, #4                      \n"
-      "st1       {v18.s}[0], [%0], %6            \n"
-      "st1       {v18.s}[1], [%0], %6            \n"
-      "st1       {v18.s}[2], [%0], %6            \n"
-      "st1       {v18.s}[3], [%0]                \n"
-
-      "mov       %0, %3                          \n"
-
-      "st1       {v17.s}[0], [%0], %7            \n"
-      "st1       {v17.s}[1], [%0], %7            \n"
-      "st1       {v17.s}[2], [%0], %7            \n"
-      "st1       {v17.s}[3], [%0], %7            \n"
-
-      "add       %0, %3, #4                      \n"
-      "st1       {v19.s}[0],  [%0], %7           \n"
-      "st1       {v19.s}[1],  [%0], %7           \n"
-      "st1       {v19.s}[2],  [%0], %7           \n"
-      "st1       {v19.s}[3],  [%0]               \n"
-
-      "add       %1, %1, #8                      \n"  // src   += 4 * 2
-      "add       %2, %2, %6, lsl #2              \n"  // dst_a += 4 *
-                                                      // dst_stride_a
-      "add       %3, %3, %7, lsl #2              \n"  // dst_b += 4 *
-                                                      // dst_stride_b
-      "subs      %w4,  %w4,  #4                  \n"  // w     -= 4
-      "b.eq      4f                              \n"
-
-      // some residual, check to see if it includes a 2x8 block,
-      // or less
-      "cmp       %w4, #2                         \n"
-      "b.lt      3f                              \n"
-
-      // 2x8 block
-      "2:                                        \n"
-      "mov       %0, %1                          \n"
-      "ld2       {v0.h, v1.h}[0], [%0], %5       \n"
-      "ld2       {v2.h, v3.h}[0], [%0], %5       \n"
-      "ld2       {v0.h, v1.h}[1], [%0], %5       \n"
-      "ld2       {v2.h, v3.h}[1], [%0], %5       \n"
-      "ld2       {v0.h, v1.h}[2], [%0], %5       \n"
-      "ld2       {v2.h, v3.h}[2], [%0], %5       \n"
-      "ld2       {v0.h, v1.h}[3], [%0], %5       \n"
-      "ld2       {v2.h, v3.h}[3], [%0]           \n"
-
-      "trn1      v4.8b, v0.8b, v2.8b             \n"
-      "trn2      v5.8b, v0.8b, v2.8b             \n"
-      "trn1      v6.8b, v1.8b, v3.8b             \n"
-      "trn2      v7.8b, v1.8b, v3.8b             \n"
-
-      "mov       %0, %2                          \n"
-
-      "st1       {v4.d}[0], [%0], %6             \n"
-      "st1       {v6.d}[0], [%0]                 \n"
-
-      "mov       %0, %3                          \n"
-
-      "st1       {v5.d}[0], [%0], %7             \n"
-      "st1       {v7.d}[0], [%0]                 \n"
-
-      "add       %1, %1, #4                      \n"  // src   += 2 * 2
-      "add       %2, %2, %6, lsl #1              \n"  // dst_a += 2 *
-                                                      // dst_stride_a
-      "add       %3, %3, %7, lsl #1              \n"  // dst_b += 2 *
-                                                      // dst_stride_b
-      "subs      %w4,  %w4,  #2                  \n"  // w     -= 2
-      "b.eq      4f                              \n"
-
-      // 1x8 block
-      "3:                                        \n"
-      "ld2       {v0.b, v1.b}[0], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[1], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[2], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[3], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[4], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[5], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[6], [%1], %5       \n"
-      "ld2       {v0.b, v1.b}[7], [%1]           \n"
-
-      "st1       {v0.d}[0], [%2]                 \n"
-      "st1       {v1.d}[0], [%3]                 \n"
-
-      "4:                                        \n"
-
-      : "=&r"(src_temp),               // %0
-        "+r"(src),                     // %1
-        "+r"(dst_a),                   // %2
-        "+r"(dst_b),                   // %3
-        "+r"(width)                    // %4
-      : "r"((ptrdiff_t)src_stride),    // %5
-        "r"((ptrdiff_t)dst_stride_a),  // %6
-        "r"((ptrdiff_t)dst_stride_b),  // %7
-        "r"(&kVTbl4x4TransposeDi)      // %8
+      : [temp] "=&r"(temp),                           // %[temp]
+        [src] "+r"(src),                              // %[src]
+        [dst_a] "+r"(dst_a),                          // %[dst_a]
+        [dst_b] "+r"(dst_b),                          // %[dst_b]
+        [width] "+r"(width)                           // %[width]
+      : [src_stride] "r"((ptrdiff_t)src_stride),      // %[src_stride]
+        [dst_stride_a] "r"((ptrdiff_t)dst_stride_a),  // %[dst_stride_a]
+        [dst_stride_b] "r"((ptrdiff_t)dst_stride_b)   // %[dst_stride_b]
       : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
         "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v30", "v31");
 }
@@ -450,7 +241,7 @@
   uint8_t* dst3 = dst2 + dst_stride;
   asm volatile(
       // Main loop transpose 4x4.  Read a column, write a row.
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.s, v1.s, v2.s, v3.s}[0], [%0], %9 \n"
       "ld4         {v0.s, v1.s, v2.s, v3.s}[1], [%1], %9 \n"
       "ld4         {v0.s, v1.s, v2.s, v3.s}[2], [%2], %9 \n"
diff --git a/source/rotate_sme.cc b/source/rotate_sme.cc
new file mode 100644
index 0000000..dc9ab0c
--- /dev/null
+++ b/source/rotate_sme.cc
@@ -0,0 +1,174 @@
+/*
+ *  Copyright 2024 The LibYuv 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 "libyuv/rotate_row.h"
+#include "libyuv/row.h"
+
+#include "libyuv/basic_types.h"
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+
+__arm_locally_streaming __arm_new("za") void TransposeWxH_SME(
+    const uint8_t* src,
+    int src_stride,
+    uint8_t* dst,
+    int dst_stride,
+    int width,
+    int height) {
+  int vl;
+  asm("cntb %x0" : "=r"(vl));
+
+  do {
+    const uint8_t* src2 = src;
+    uint8_t* dst2 = dst;
+
+    // Process up to VL elements per iteration of the inner loop.
+    int block_height = height > vl ? vl : height;
+
+    int width2 = width;
+    do {
+      const uint8_t* src3 = src2;
+
+      // Process up to VL elements per iteration of the inner loop.
+      int block_width = width2 > vl ? vl : width2;
+
+      asm volatile(
+          "mov     w12, #0                              \n"
+
+          // Create a predicate to handle loading partial rows.
+          "whilelt p0.b, wzr, %w[block_width]           \n"
+
+          // Load H <= VL rows into ZA0.
+          "1:                                           \n"
+          "ld1b    {za0h.b[w12, 0]}, p0/z, [%[src3]]    \n"
+          "add     %[src3], %[src3], %[src_stride]      \n"
+          "add     w12, w12, #1                         \n"
+          "cmp     w12, %w[block_height]                \n"
+          "b.ne    1b                                   \n"
+
+          // Create a predicate to handle storing partial columns.
+          "whilelt p0.b, wzr, %w[block_height]          \n"
+          "mov     w12, #0                              \n"
+
+          // Store W <= VL columns from ZA0.
+          "2:                                           \n"
+          "st1b    {za0v.b[w12, 0]}, p0, [%[dst2]]      \n"
+          "add     %[dst2], %[dst2], %[dst_stride]      \n"
+          "add     w12, w12, #1                         \n"
+          "cmp     w12, %w[block_width]                 \n"
+          "b.ne    2b                                   \n"
+          : [src3] "+r"(src3),                        // %[src3]
+            [dst2] "+r"(dst2)                         // %[dst2]
+          : [src_stride] "r"((ptrdiff_t)src_stride),  // %[src_stride]
+            [dst_stride] "r"((ptrdiff_t)dst_stride),  // %[dst_stride]
+            [block_width] "r"(block_width),           // %[block_width]
+            [block_height] "r"(block_height)          // %[block_height]
+          : "cc", "memory", "p0", "w12", "za");
+
+      src2 += vl;
+      width2 -= vl;
+    } while (width2 > 0);
+
+    src += vl * src_stride;
+    dst += vl;
+    height -= vl;
+  } while (height > 0);
+}
+
+__arm_locally_streaming __arm_new("za") void TransposeUVWxH_SME(
+    const uint8_t* src,
+    int src_stride,
+    uint8_t* dst_a,
+    int dst_stride_a,
+    uint8_t* dst_b,
+    int dst_stride_b,
+    int width,
+    int height) {
+  int vl;
+  asm("cnth %x0" : "=r"(vl));
+
+  do {
+    const uint8_t* src2 = src;
+    uint8_t* dst2_a = dst_a;
+    uint8_t* dst2_b = dst_b;
+
+    // Process up to VL bytes per iteration of the inner loop.
+    int block_height = height > vl * 2 ? vl * 2 : height;
+
+    int width2 = width;
+    do {
+      const uint8_t* src3 = src2;
+
+      // Process up to VL 16-bit elements per iteration of the inner loop.
+      int block_width = width2 > vl ? vl : width2;
+
+      asm volatile(
+          "mov      w12, #0                               \n"
+
+          // Create a predicate to handle loading partial rows,
+          // %[block_width] is always a multiple of two here.
+          "whilelt  p0.b, wzr, %w[block_width]            \n"
+
+          // Load H <= VL rows into ZA0, such that U/V components exist in
+          // alternating columns.
+          "1:                                             \n"
+          "ld1b     {za0h.b[w12, 0]}, p0/z, [%[src]]      \n"
+          "add      %[src], %[src], %[src_stride]         \n"
+          "add      w12, w12, #1                          \n"
+          "cmp      w12, %w[block_height]                 \n"
+          "b.ne     1b                                    \n"
+
+          // Create a predicate to handle storing partial columns.
+          "whilelt  p0.b, wzr, %w[block_height]           \n"
+          "mov      w12, #0                               \n"
+
+          // Store alternating UV data from pairs of ZA0 columns.
+          "2:                                             \n"
+          "st1b     {za0v.b[w12, 0]}, p0, [%[dst_a]]      \n"
+          "st1b     {za0v.b[w12, 1]}, p0, [%[dst_b]]      \n"
+          "add      %[dst_a], %[dst_a], %[dst_stride_a]   \n"
+          "add      %[dst_b], %[dst_b], %[dst_stride_b]   \n"
+          "add      w12, w12, #2                          \n"
+          "cmp      w12, %w[block_width]                  \n"
+          "b.ne     2b                                    \n"
+          : [src] "+r"(src3),                             // %[src]
+            [dst_a] "+r"(dst2_a),                         // %[dst_a]
+            [dst_b] "+r"(dst2_b)                          // %[dst_b]
+          : [src_stride] "r"((ptrdiff_t)src_stride),      // %[src_stride]
+            [dst_stride_a] "r"((ptrdiff_t)dst_stride_a),  // %[dst_stride_a]
+            [dst_stride_b] "r"((ptrdiff_t)dst_stride_b),  // %[dst_stride_b]
+            [block_width] "r"(block_width * 2),           // %[block_width]
+            [block_height] "r"(block_height)              // %[block_height]
+          : "cc", "memory", "p0", "w12", "za");
+
+      src2 += 2 * vl;
+      width2 -= vl;
+    } while (width2 > 0);
+
+    src += 2 * vl * src_stride;
+    dst_a += 2 * vl;
+    dst_b += 2 * vl;
+    height -= 2 * vl;
+  } while (height > 0);
+}
+
+#endif  // !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) &&
+        // defined(__aarch64__)
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
diff --git a/source/rotate_win.cc b/source/rotate_win.cc
index a78873f..03eeee3 100644
--- a/source/rotate_win.cc
+++ b/source/rotate_win.cc
@@ -17,8 +17,8 @@
 #endif
 
 // This module is for 32 bit Visual C x86
-#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && \
-    !defined(__clang__) && defined(_M_IX86)
+#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && defined(_M_IX86) && \
+    (!defined(__clang__) || defined(LIBYUV_ENABLE_ROWWIN))
 
 __declspec(naked) void TransposeWx8_SSSE3(const uint8_t* src,
                                           int src_stride,
diff --git a/source/row_any.cc b/source/row_any.cc
index e574543..85fb6ff 100644
--- a/source/row_any.cc
+++ b/source/row_any.cc
@@ -142,6 +142,27 @@
     memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, vout, SS(r, DUVSHIFT) * BPP);      \
   }
 
+#ifdef HAS_I210ALPHATOARGBROW_NEON
+ANY41CT(I210AlphaToARGBRow_Any_NEON,
+        I210AlphaToARGBRow_NEON,
+        1,
+        0,
+        uint16_t,
+        2,
+        4,
+        7)
+#endif
+#ifdef HAS_I410ALPHATOARGBROW_NEON
+ANY41CT(I410AlphaToARGBRow_Any_NEON,
+        I410AlphaToARGBRow_NEON,
+        0,
+        0,
+        uint16_t,
+        2,
+        4,
+        7)
+#endif
+
 #ifdef HAS_I210ALPHATOARGBROW_SSSE3
 ANY41CT(I210AlphaToARGBRow_Any_SSSE3,
         I210AlphaToARGBRow_SSSE3,
@@ -399,6 +420,9 @@
 #ifdef HAS_I444TORGB24ROW_NEON
 ANY31C(I444ToRGB24Row_Any_NEON, I444ToRGB24Row_NEON, 0, 0, 3, 7)
 #endif
+#ifdef HAS_I422TOAR30ROW_NEON
+ANY31C(I422ToAR30Row_Any_NEON, I422ToAR30Row_NEON, 1, 0, 4, 7)
+#endif
 #ifdef HAS_I422TOARGBROW_NEON
 ANY31C(I444ToARGBRow_Any_NEON, I444ToARGBRow_NEON, 0, 0, 4, 7)
 ANY31C(I422ToARGBRow_Any_NEON, I422ToARGBRow_NEON, 1, 0, 4, 7)
@@ -495,6 +519,24 @@
 #ifdef HAS_I212TOAR30ROW_AVX2
 ANY31CT(I212ToAR30Row_Any_AVX2, I212ToAR30Row_AVX2, 1, 0, uint16_t, 2, 4, 15)
 #endif
+#ifdef HAS_I210TOARGBROW_NEON
+ANY31CT(I210ToARGBRow_Any_NEON, I210ToARGBRow_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_I410TOARGBROW_NEON
+ANY31CT(I410ToARGBRow_Any_NEON, I410ToARGBRow_NEON, 0, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_I210TOAR30ROW_NEON
+ANY31CT(I210ToAR30Row_Any_NEON, I210ToAR30Row_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_I410TOAR30ROW_NEON
+ANY31CT(I410ToAR30Row_Any_NEON, I410ToAR30Row_NEON, 0, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_I212TOARGBROW_NEON
+ANY31CT(I212ToARGBRow_Any_NEON, I212ToARGBRow_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_I212TOAR30ROW_NEON
+ANY31CT(I212ToAR30Row_Any_NEON, I212ToAR30Row_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
 #undef ANY31CT
 
 // Any 3 planes to 1 plane with parameter
@@ -528,7 +570,7 @@
         2,
         uint8_t,
         4,
-        3)
+        7)
 #endif
 
 #ifdef HAS_MERGEXR64ROW_AVX2
@@ -855,6 +897,12 @@
 #ifdef HAS_P210TOAR30ROW_AVX2
 ANY21CT(P210ToAR30Row_Any_AVX2, P210ToAR30Row_AVX2, 1, 0, uint16_t, 2, 4, 15)
 #endif
+#ifdef HAS_P210TOAR30ROW_NEON
+ANY21CT(P210ToAR30Row_Any_NEON, P210ToAR30Row_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_P210TOARGBROW_NEON
+ANY21CT(P210ToARGBRow_Any_NEON, P210ToARGBRow_NEON, 1, 0, uint16_t, 2, 4, 7)
+#endif
 #ifdef HAS_P410TOAR30ROW_SSSE3
 ANY21CT(P410ToAR30Row_Any_SSSE3, P410ToAR30Row_SSSE3, 0, 0, uint16_t, 2, 4, 7)
 #endif
@@ -867,6 +915,12 @@
 #ifdef HAS_P410TOAR30ROW_AVX2
 ANY21CT(P410ToAR30Row_Any_AVX2, P410ToAR30Row_AVX2, 0, 0, uint16_t, 2, 4, 15)
 #endif
+#ifdef HAS_P410TOAR30ROW_NEON
+ANY21CT(P410ToAR30Row_Any_NEON, P410ToAR30Row_NEON, 0, 0, uint16_t, 2, 4, 7)
+#endif
+#ifdef HAS_P410TOARGBROW_NEON
+ANY21CT(P410ToARGBRow_Any_NEON, P410ToARGBRow_NEON, 0, 0, uint16_t, 2, 4, 7)
+#endif
 
 #undef ANY21CT
 
@@ -913,6 +967,9 @@
     memcpy(dst_ptr + n * BPP, vout, r * BPP);                            \
   }
 
+#ifdef HAS_COPYROW_AVX512BW
+ANY11(CopyRow_Any_AVX512BW, CopyRow_AVX512BW, 0, 1, 1, 127)
+#endif
 #ifdef HAS_COPYROW_AVX
 ANY11(CopyRow_Any_AVX, CopyRow_AVX, 0, 1, 1, 63)
 #endif
@@ -948,6 +1005,12 @@
 #if defined(HAS_ABGRTOAR30ROW_SSSE3)
 ANY11(ABGRToAR30Row_Any_SSSE3, ABGRToAR30Row_SSSE3, 0, 4, 4, 3)
 #endif
+#if defined(HAS_ABGRTOAR30ROW_NEON)
+ANY11(ABGRToAR30Row_Any_NEON, ABGRToAR30Row_NEON, 0, 4, 4, 7)
+#endif
+#if defined(HAS_ARGBTOAR30ROW_NEON)
+ANY11(ARGBToAR30Row_Any_NEON, ARGBToAR30Row_NEON, 0, 4, 4, 7)
+#endif
 #if defined(HAS_ARGBTOAR30ROW_SSSE3)
 ANY11(ARGBToAR30Row_Any_SSSE3, ARGBToAR30Row_SSSE3, 0, 4, 4, 3)
 #endif
@@ -970,6 +1033,9 @@
 ANY11(ARGB1555ToARGBRow_Any_SSE2, ARGB1555ToARGBRow_SSE2, 0, 2, 4, 7)
 ANY11(ARGB4444ToARGBRow_Any_SSE2, ARGB4444ToARGBRow_SSE2, 0, 2, 4, 7)
 #endif
+#if defined(HAS_RAWTOARGBROW_AVX2)
+ANY11(RAWToARGBRow_Any_AVX2, RAWToARGBRow_AVX2, 0, 3, 4, 31)
+#endif
 #if defined(HAS_RAWTORGBAROW_SSSE3)
 ANY11(RAWToRGBARow_Any_SSSE3, RAWToRGBARow_SSSE3, 0, 3, 4, 15)
 #endif
@@ -1072,6 +1138,9 @@
 #ifdef HAS_ARGBTOYROW_NEON
 ANY11(ARGBToYRow_Any_NEON, ARGBToYRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_ARGBTOYROW_NEON_DOTPROD
+ANY11(ARGBToYRow_Any_NEON_DotProd, ARGBToYRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_ARGBTOYROW_MSA
 ANY11(ARGBToYRow_Any_MSA, ARGBToYRow_MSA, 0, 4, 1, 15)
 #endif
@@ -1084,12 +1153,21 @@
 #ifdef HAS_ARGBTOYJROW_NEON
 ANY11(ARGBToYJRow_Any_NEON, ARGBToYJRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_ARGBTOYJROW_NEON_DOTPROD
+ANY11(ARGBToYJRow_Any_NEON_DotProd, ARGBToYJRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_ABGRTOYJROW_NEON
 ANY11(ABGRToYJRow_Any_NEON, ABGRToYJRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_ABGRTOYJROW_NEON_DOTPROD
+ANY11(ABGRToYJRow_Any_NEON_DotProd, ABGRToYJRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_RGBATOYJROW_NEON
 ANY11(RGBAToYJRow_Any_NEON, RGBAToYJRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_RGBATOYJROW_NEON_DOTPROD
+ANY11(RGBAToYJRow_Any_NEON_DotProd, RGBAToYJRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_ARGBTOYJROW_MSA
 ANY11(ARGBToYJRow_Any_MSA, ARGBToYJRow_MSA, 0, 4, 1, 15)
 #endif
@@ -1114,6 +1192,9 @@
 #ifdef HAS_BGRATOYROW_NEON
 ANY11(BGRAToYRow_Any_NEON, BGRAToYRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_BGRATOYROW_NEON_DOTPROD
+ANY11(BGRAToYRow_Any_NEON_DotProd, BGRAToYRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_BGRATOYROW_MSA
 ANY11(BGRAToYRow_Any_MSA, BGRAToYRow_MSA, 0, 4, 1, 15)
 #endif
@@ -1126,6 +1207,9 @@
 #ifdef HAS_ABGRTOYROW_NEON
 ANY11(ABGRToYRow_Any_NEON, ABGRToYRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_ABGRTOYROW_NEON_DOTPROD
+ANY11(ABGRToYRow_Any_NEON_DotProd, ABGRToYRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_ABGRTOYROW_MSA
 ANY11(ABGRToYRow_Any_MSA, ABGRToYRow_MSA, 0, 4, 1, 7)
 #endif
@@ -1138,6 +1222,9 @@
 #ifdef HAS_RGBATOYROW_NEON
 ANY11(RGBAToYRow_Any_NEON, RGBAToYRow_NEON, 0, 4, 1, 15)
 #endif
+#ifdef HAS_RGBATOYROW_NEON_DOTPROD
+ANY11(RGBAToYRow_Any_NEON_DotProd, RGBAToYRow_NEON_DotProd, 0, 4, 1, 15)
+#endif
 #ifdef HAS_RGBATOYROW_MSA
 ANY11(RGBAToYRow_Any_MSA, RGBAToYRow_MSA, 0, 4, 1, 15)
 #endif
@@ -1202,7 +1289,7 @@
 ANY11(RAWToYJRow_Any_LASX, RAWToYJRow_LASX, 0, 3, 1, 31)
 #endif
 #ifdef HAS_RGB565TOYROW_NEON
-ANY11(RGB565ToYRow_Any_NEON, RGB565ToYRow_NEON, 0, 2, 1, 7)
+ANY11(RGB565ToYRow_Any_NEON, RGB565ToYRow_NEON, 0, 2, 1, 15)
 #endif
 #ifdef HAS_RGB565TOYROW_MSA
 ANY11(RGB565ToYRow_Any_MSA, RGB565ToYRow_MSA, 0, 2, 1, 15)
@@ -1214,8 +1301,12 @@
 ANY11(RGB565ToYRow_Any_LASX, RGB565ToYRow_LASX, 0, 2, 1, 31)
 #endif
 #ifdef HAS_ARGB1555TOYROW_NEON
+#ifdef __aarch64__
+ANY11(ARGB1555ToYRow_Any_NEON, ARGB1555ToYRow_NEON, 0, 2, 1, 15)
+#else
 ANY11(ARGB1555ToYRow_Any_NEON, ARGB1555ToYRow_NEON, 0, 2, 1, 7)
 #endif
+#endif
 #ifdef HAS_ARGB1555TOYROW_MSA
 ANY11(ARGB1555ToYRow_Any_MSA, ARGB1555ToYRow_MSA, 0, 2, 1, 15)
 #endif
@@ -1226,8 +1317,12 @@
 ANY11(ARGB1555ToYRow_Any_LASX, ARGB1555ToYRow_LASX, 0, 2, 1, 31)
 #endif
 #ifdef HAS_ARGB4444TOYROW_NEON
+#ifdef __aarch64__
+ANY11(ARGB4444ToYRow_Any_NEON, ARGB4444ToYRow_NEON, 0, 2, 1, 15)
+#else
 ANY11(ARGB4444ToYRow_Any_NEON, ARGB4444ToYRow_NEON, 0, 2, 1, 7)
 #endif
+#endif
 #ifdef HAS_YUY2TOYROW_NEON
 ANY11(YUY2ToYRow_Any_NEON, YUY2ToYRow_NEON, 1, 4, 1, 15)
 #endif
@@ -1292,7 +1387,7 @@
 ANY11(RAWToARGBRow_Any_LASX, RAWToARGBRow_LASX, 0, 3, 4, 31)
 #endif
 #ifdef HAS_RGB565TOARGBROW_NEON
-ANY11(RGB565ToARGBRow_Any_NEON, RGB565ToARGBRow_NEON, 0, 2, 4, 7)
+ANY11(RGB565ToARGBRow_Any_NEON, RGB565ToARGBRow_NEON, 0, 2, 4, 15)
 #endif
 #ifdef HAS_RGB565TOARGBROW_MSA
 ANY11(RGB565ToARGBRow_Any_MSA, RGB565ToARGBRow_MSA, 0, 2, 4, 15)
@@ -1304,7 +1399,7 @@
 ANY11(RGB565ToARGBRow_Any_LASX, RGB565ToARGBRow_LASX, 0, 2, 4, 31)
 #endif
 #ifdef HAS_ARGB1555TOARGBROW_NEON
-ANY11(ARGB1555ToARGBRow_Any_NEON, ARGB1555ToARGBRow_NEON, 0, 2, 4, 7)
+ANY11(ARGB1555ToARGBRow_Any_NEON, ARGB1555ToARGBRow_NEON, 0, 2, 4, 15)
 #endif
 #ifdef HAS_ARGB1555TOARGBROW_MSA
 ANY11(ARGB1555ToARGBRow_Any_MSA, ARGB1555ToARGBRow_MSA, 0, 2, 4, 15)
@@ -1595,8 +1690,8 @@
 // Any 1 to 1 with parameter and shorts.  BPP measures in shorts.
 #define ANY11C(NAMEANY, ANY_SIMD, SBPP, BPP, STYPE, DTYPE, MASK)             \
   void NAMEANY(const STYPE* src_ptr, DTYPE* dst_ptr, int scale, int width) { \
-    SIMD_ALIGNED(STYPE vin[32]);                                             \
-    SIMD_ALIGNED(DTYPE vout[32]);                                            \
+    SIMD_ALIGNED(STYPE vin[64]);                                             \
+    SIMD_ALIGNED(DTYPE vout[64]);                                            \
     memset(vin, 0, sizeof(vin)); /* for msan */                              \
     int r = width & MASK;                                                    \
     int n = width & ~MASK;                                                   \
@@ -1626,6 +1721,15 @@
        uint8_t,
        31)
 #endif
+#ifdef HAS_CONVERT16TO8ROW_AVX512BW
+ANY11C(Convert16To8Row_Any_AVX512BW,
+       Convert16To8Row_AVX512BW,
+       2,
+       1,
+       uint16_t,
+       uint8_t,
+       63)
+#endif
 #ifdef HAS_CONVERT16TO8ROW_NEON
 ANY11C(Convert16To8Row_Any_NEON,
        Convert16To8Row_NEON,
@@ -1679,6 +1783,43 @@
 #endif
 #undef ANY11C
 
+// Any 1 to 1 with parameter and shorts.  BPP measures in shorts.
+#define ANY11SB(NAMEANY, ANY_SIMD, SBPP, BPP, STYPE, DTYPE, MASK)         \
+  void NAMEANY(const STYPE* src_ptr, DTYPE* dst_ptr, int scale, int bias, \
+               int width) {                                               \
+    SIMD_ALIGNED(STYPE vin[64]);                                          \
+    SIMD_ALIGNED(DTYPE vout[64]);                                         \
+    memset(vin, 0, sizeof(vin)); /* for msan */                           \
+    int r = width & MASK;                                                 \
+    int n = width & ~MASK;                                                \
+    if (n > 0) {                                                          \
+      ANY_SIMD(src_ptr, dst_ptr, scale, bias, n);                         \
+    }                                                                     \
+    memcpy(vin, src_ptr + n, r * SBPP);                                   \
+    ANY_SIMD(vin, vout, scale, bias, MASK + 1);                           \
+    memcpy(dst_ptr + n, vout, r * BPP);                                   \
+  }
+
+#ifdef HAS_CONVERT8TO8ROW_NEON
+ANY11SB(Convert8To8Row_Any_NEON,
+        Convert8To8Row_NEON,
+        1,
+        1,
+        uint8_t,
+        uint8_t,
+        31)
+#endif
+#ifdef HAS_CONVERT8TO8ROW_AVX2
+ANY11SB(Convert8To8Row_Any_AVX2,
+        Convert8To8Row_AVX2,
+        1,
+        1,
+        uint8_t,
+        uint8_t,
+        31)
+#endif
+#undef ANY11B
+
 // Any 1 to 1 with parameter and shorts to byte.  BPP measures in shorts.
 #define ANY11P16(NAMEANY, ANY_SIMD, ST, T, SBPP, BPP, MASK)             \
   void NAMEANY(const ST* src_ptr, T* dst_ptr, float param, int width) { \
@@ -1712,14 +1853,7 @@
          15)
 #endif
 #ifdef HAS_HALFFLOATROW_NEON
-ANY11P16(HalfFloatRow_Any_NEON, HalfFloatRow_NEON, uint16_t, uint16_t, 2, 2, 7)
-ANY11P16(HalfFloat1Row_Any_NEON,
-         HalfFloat1Row_NEON,
-         uint16_t,
-         uint16_t,
-         2,
-         2,
-         7)
+ANY11P16(HalfFloatRow_Any_NEON, HalfFloatRow_NEON, uint16_t, uint16_t, 2, 2, 15)
 #endif
 #ifdef HAS_HALFFLOATROW_MSA
 ANY11P16(HalfFloatRow_Any_MSA, HalfFloatRow_MSA, uint16_t, uint16_t, 2, 2, 31)
@@ -2014,6 +2148,15 @@
 #ifdef HAS_ARGBTOUV444ROW_SSSE3
 ANY12(ARGBToUV444Row_Any_SSSE3, ARGBToUV444Row_SSSE3, 0, 4, 0, 15)
 #endif
+#ifdef HAS_ARGBTOUVJ444ROW_SSSE3
+ANY12(ARGBToUVJ444Row_Any_SSSE3, ARGBToUVJ444Row_SSSE3, 0, 4, 0, 15)
+#endif
+#ifdef HAS_ARGBTOUV444ROW_AVX2
+ANY12(ARGBToUV444Row_Any_AVX2, ARGBToUV444Row_AVX2, 0, 4, 0, 31)
+#endif
+#ifdef HAS_ARGBTOUVJ444ROW_AVX2
+ANY12(ARGBToUVJ444Row_Any_AVX2, ARGBToUVJ444Row_AVX2, 0, 4, 0, 31)
+#endif
 #ifdef HAS_YUY2TOUV422ROW_AVX2
 ANY12(YUY2ToUV422Row_Any_AVX2, YUY2ToUV422Row_AVX2, 1, 4, 1, 31)
 ANY12(UYVYToUV422Row_Any_AVX2, UYVYToUV422Row_AVX2, 1, 4, 1, 31)
@@ -2024,9 +2167,14 @@
 #endif
 #ifdef HAS_YUY2TOUV422ROW_NEON
 ANY12(ARGBToUV444Row_Any_NEON, ARGBToUV444Row_NEON, 0, 4, 0, 7)
+ANY12(ARGBToUVJ444Row_Any_NEON, ARGBToUVJ444Row_NEON, 0, 4, 0, 7)
 ANY12(YUY2ToUV422Row_Any_NEON, YUY2ToUV422Row_NEON, 1, 4, 1, 15)
 ANY12(UYVYToUV422Row_Any_NEON, UYVYToUV422Row_NEON, 1, 4, 1, 15)
 #endif
+#ifdef HAS_ARGBTOUV444ROW_NEON_I8MM
+ANY12(ARGBToUV444Row_Any_NEON_I8MM, ARGBToUV444Row_NEON_I8MM, 0, 4, 0, 7)
+ANY12(ARGBToUVJ444Row_Any_NEON_I8MM, ARGBToUVJ444Row_NEON_I8MM, 0, 4, 0, 7)
+#endif
 #ifdef HAS_YUY2TOUV422ROW_MSA
 ANY12(ARGBToUV444Row_Any_MSA, ARGBToUV444Row_MSA, 0, 4, 0, 15)
 ANY12(YUY2ToUV422Row_Any_MSA, YUY2ToUV422Row_MSA, 1, 4, 1, 31)
@@ -2093,6 +2241,12 @@
 #ifdef HAS_SPLITRGBROW_SSSE3
 ANY13(SplitRGBRow_Any_SSSE3, SplitRGBRow_SSSE3, 3, 15)
 #endif
+#ifdef HAS_SPLITRGBROW_SSE41
+ANY13(SplitRGBRow_Any_SSE41, SplitRGBRow_SSE41, 3, 15)
+#endif
+#ifdef HAS_SPLITRGBROW_AVX2
+ANY13(SplitRGBRow_Any_AVX2, SplitRGBRow_AVX2, 3, 31)
+#endif
 #ifdef HAS_SPLITRGBROW_NEON
 ANY13(SplitRGBRow_Any_NEON, SplitRGBRow_NEON, 3, 15)
 #endif
@@ -2204,6 +2358,9 @@
 #ifdef HAS_ARGBTOUVROW_NEON
 ANY12S(ARGBToUVRow_Any_NEON, ARGBToUVRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_ARGBTOUVROW_SVE2
+ANY12S(ARGBToUVRow_Any_SVE2, ARGBToUVRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_ARGBTOUVROW_MSA
 ANY12S(ARGBToUVRow_Any_MSA, ARGBToUVRow_MSA, 0, 4, 31)
 #endif
@@ -2216,9 +2373,15 @@
 #ifdef HAS_ARGBTOUVJROW_NEON
 ANY12S(ARGBToUVJRow_Any_NEON, ARGBToUVJRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_ARGBTOUVJROW_SVE2
+ANY12S(ARGBToUVJRow_Any_SVE2, ARGBToUVJRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_ABGRTOUVJROW_NEON
 ANY12S(ABGRToUVJRow_Any_NEON, ABGRToUVJRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_ABGRTOUVJROW_SVE2
+ANY12S(ABGRToUVJRow_Any_SVE2, ABGRToUVJRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_ARGBTOUVJROW_MSA
 ANY12S(ARGBToUVJRow_Any_MSA, ARGBToUVJRow_MSA, 0, 4, 31)
 #endif
@@ -2231,6 +2394,9 @@
 #ifdef HAS_BGRATOUVROW_NEON
 ANY12S(BGRAToUVRow_Any_NEON, BGRAToUVRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_BGRATOUVROW_SVE2
+ANY12S(BGRAToUVRow_Any_SVE2, BGRAToUVRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_BGRATOUVROW_MSA
 ANY12S(BGRAToUVRow_Any_MSA, BGRAToUVRow_MSA, 0, 4, 15)
 #endif
@@ -2240,6 +2406,9 @@
 #ifdef HAS_ABGRTOUVROW_NEON
 ANY12S(ABGRToUVRow_Any_NEON, ABGRToUVRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_ABGRTOUVROW_SVE2
+ANY12S(ABGRToUVRow_Any_SVE2, ABGRToUVRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_ABGRTOUVROW_MSA
 ANY12S(ABGRToUVRow_Any_MSA, ABGRToUVRow_MSA, 0, 4, 15)
 #endif
@@ -2249,6 +2418,9 @@
 #ifdef HAS_RGBATOUVROW_NEON
 ANY12S(RGBAToUVRow_Any_NEON, RGBAToUVRow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_RGBATOUVROW_SVE2
+ANY12S(RGBAToUVRow_Any_SVE2, RGBAToUVRow_SVE2, 0, 4, 1)
+#endif
 #ifdef HAS_RGBATOUVROW_MSA
 ANY12S(RGBAToUVRow_Any_MSA, RGBAToUVRow_MSA, 0, 4, 15)
 #endif
@@ -2368,6 +2540,12 @@
 ANY11S(AYUVToUVRow_Any_NEON, AYUVToUVRow_NEON, 0, 4, 15)
 ANY11S(AYUVToVURow_Any_NEON, AYUVToVURow_NEON, 0, 4, 15)
 #endif
+#ifdef HAS_AYUVTOUVROW_SVE2
+ANY11S(AYUVToUVRow_Any_SVE2, AYUVToUVRow_SVE2, 0, 4, 1)
+#endif
+#ifdef HAS_AYUVTOVUROW_SVE2
+ANY11S(AYUVToVURow_Any_SVE2, AYUVToVURow_SVE2, 0, 4, 1)
+#endif
 #undef ANY11S
 
 #define ANYDETILE(NAMEANY, ANY_SIMD, T, BPP, MASK)                           \
diff --git a/source/row_common.cc b/source/row_common.cc
index 3afc4b4..7101ec3 100644
--- a/source/row_common.cc
+++ b/source/row_common.cc
@@ -36,18 +36,9 @@
 // LIBYUV_UNLIMITED_BT709
 // LIBYUV_UNLIMITED_BT2020
 
-// The following macro from row_win makes the C code match the row_win code,
-// which is 7 bit fixed point for ARGBToI420:
-#if !defined(LIBYUV_BIT_EXACT) && !defined(LIBYUV_DISABLE_X86) && \
-    defined(_MSC_VER) && !defined(__clang__) &&                   \
-    (defined(_M_IX86) || defined(_M_X64))
-#define LIBYUV_RGB7 1
-#endif
-
 #if !defined(LIBYUV_BIT_EXACT) && (defined(__x86_64__) || defined(_M_X64) || \
                                    defined(__i386__) || defined(_M_IX86))
 #define LIBYUV_ARGBTOUV_PAVGB 1
-#define LIBYUV_RGBTOU_TRUNCATE 1
 #endif
 #if defined(LIBYUV_BIT_EXACT)
 #define LIBYUV_UNATTENUATE_DUP 1
@@ -56,7 +47,7 @@
 // llvm x86 is poor at ternary operator, so use branchless min/max.
 
 #define USE_BRANCHLESS 1
-#if USE_BRANCHLESS
+#if defined(USE_BRANCHLESS)
 static __inline int32_t clamp0(int32_t v) {
   return -(v >= 0) & v;
 }
@@ -624,59 +615,33 @@
     dst_ar64_16 += 4;
   }
 }
-
-#ifdef LIBYUV_RGB7
-// Old 7 bit math for compatibility on unsupported platforms.
-static __inline uint8_t RGBToY(uint8_t r, uint8_t g, uint8_t b) {
-  return STATIC_CAST(uint8_t, ((33 * r + 65 * g + 13 * b) >> 7) + 16);
-}
-#else
-// 8 bit
-// Intel SSE/AVX uses the following equivalent formula
-// 0x7e80 = (66 + 129 + 25) * -128 + 0x1000 (for +16) and 0x0080 for round.
-//  return (66 * ((int)r - 128) + 129 * ((int)g - 128) + 25 * ((int)b - 128) +
-//  0x7e80) >> 8;
+// BT601 8 bit Y:
+// b 0.114 * 219 = 24.966  = 25
+// g 0.587 * 219 = 128.553 = 129
+// r 0.299 * 219 = 65.481  = 66
+// BT601 8 bit U:
+// b  0.875  * 128 = 112.0    = 112
+// g -0.5781 * 128 = −73.9968 = -74
+// r -0.2969 * 128 = −38.0032 = -38
+// BT601 8 bit V:
+// b -0.1406 * 128 = −17.9968 = -18
+// g -0.7344 * 128 = −94.0032 = -94
+// r  0.875  * 128 = 112.0    = 112
 
 static __inline uint8_t RGBToY(uint8_t r, uint8_t g, uint8_t b) {
   return STATIC_CAST(uint8_t, (66 * r + 129 * g + 25 * b + 0x1080) >> 8);
 }
-#endif
-
-#define AVGB(a, b) (((a) + (b) + 1) >> 1)
-
-// LIBYUV_RGBTOU_TRUNCATE mimics x86 code that does not round.
-#ifdef LIBYUV_RGBTOU_TRUNCATE
 static __inline uint8_t RGBToU(uint8_t r, uint8_t g, uint8_t b) {
   return STATIC_CAST(uint8_t, (112 * b - 74 * g - 38 * r + 0x8000) >> 8);
 }
 static __inline uint8_t RGBToV(uint8_t r, uint8_t g, uint8_t b) {
   return STATIC_CAST(uint8_t, (112 * r - 94 * g - 18 * b + 0x8000) >> 8);
 }
-#else
-// TODO(fbarchard): Add rounding to x86 SIMD and use this
-static __inline uint8_t RGBToU(uint8_t r, uint8_t g, uint8_t b) {
-  return STATIC_CAST(uint8_t, (112 * b - 74 * g - 38 * r + 0x8080) >> 8);
-}
-static __inline uint8_t RGBToV(uint8_t r, uint8_t g, uint8_t b) {
-  return STATIC_CAST(uint8_t, (112 * r - 94 * g - 18 * b + 0x8080) >> 8);
-}
-#endif
-
-// LIBYUV_ARGBTOUV_PAVGB mimics x86 code that subsamples with 2 pavgb.
-#if !defined(LIBYUV_ARGBTOUV_PAVGB)
-static __inline int RGB2xToU(uint16_t r, uint16_t g, uint16_t b) {
-  return STATIC_CAST(
-      uint8_t, ((112 / 2) * b - (74 / 2) * g - (38 / 2) * r + 0x8080) >> 8);
-}
-static __inline int RGB2xToV(uint16_t r, uint16_t g, uint16_t b) {
-  return STATIC_CAST(
-      uint8_t, ((112 / 2) * r - (94 / 2) * g - (18 / 2) * b + 0x8080) >> 8);
-}
-#endif
+#define AVGB(a, b) (((a) + (b) + 1) >> 1)
 
 // ARGBToY_C and ARGBToUV_C
-// Intel version mimic SSE/AVX which does 2 pavgb
-#if LIBYUV_ARGBTOUV_PAVGB
+// Intel version of UV mimic SSE/AVX which does 2 pavgb
+#if defined(LIBYUV_ARGBTOUV_PAVGB)
 #define MAKEROWY(NAME, R, G, B, BPP)                                       \
   void NAME##ToYRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width) { \
     int x;                                                                 \
@@ -713,7 +678,7 @@
     }                                                                      \
   }
 #else
-// ARM version does sum / 2 then multiply by 2x smaller coefficients
+// ARM version does average of 4 pixels with rounding
 #define MAKEROWY(NAME, R, G, B, BPP)                                       \
   void NAME##ToYRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width) { \
     int x;                                                                 \
@@ -728,28 +693,28 @@
     const uint8_t* src_rgb1 = src_rgb + src_stride_rgb;                    \
     int x;                                                                 \
     for (x = 0; x < width - 1; x += 2) {                                   \
-      uint16_t ab = (src_rgb[B] + src_rgb[B + BPP] + src_rgb1[B] +         \
-                     src_rgb1[B + BPP] + 1) >>                             \
-                    1;                                                     \
-      uint16_t ag = (src_rgb[G] + src_rgb[G + BPP] + src_rgb1[G] +         \
-                     src_rgb1[G + BPP] + 1) >>                             \
-                    1;                                                     \
-      uint16_t ar = (src_rgb[R] + src_rgb[R + BPP] + src_rgb1[R] +         \
-                     src_rgb1[R + BPP] + 1) >>                             \
-                    1;                                                     \
-      dst_u[0] = RGB2xToU(ar, ag, ab);                                     \
-      dst_v[0] = RGB2xToV(ar, ag, ab);                                     \
+      uint8_t ab = (src_rgb[B] + src_rgb[B + BPP] + src_rgb1[B] +          \
+                    src_rgb1[B + BPP] + 2) >>                              \
+                   2;                                                      \
+      uint8_t ag = (src_rgb[G] + src_rgb[G + BPP] + src_rgb1[G] +          \
+                    src_rgb1[G + BPP] + 2) >>                              \
+                   2;                                                      \
+      uint8_t ar = (src_rgb[R] + src_rgb[R + BPP] + src_rgb1[R] +          \
+                    src_rgb1[R + BPP] + 2) >>                              \
+                   2;                                                      \
+      dst_u[0] = RGBToU(ar, ag, ab);                                       \
+      dst_v[0] = RGBToV(ar, ag, ab);                                       \
       src_rgb += BPP * 2;                                                  \
       src_rgb1 += BPP * 2;                                                 \
       dst_u += 1;                                                          \
       dst_v += 1;                                                          \
     }                                                                      \
     if (width & 1) {                                                       \
-      uint16_t ab = src_rgb[B] + src_rgb1[B];                              \
-      uint16_t ag = src_rgb[G] + src_rgb1[G];                              \
-      uint16_t ar = src_rgb[R] + src_rgb1[R];                              \
-      dst_u[0] = RGB2xToU(ar, ag, ab);                                     \
-      dst_v[0] = RGB2xToV(ar, ag, ab);                                     \
+      uint8_t ab = (src_rgb[B] + src_rgb1[B] + 1) >> 1;                    \
+      uint8_t ag = (src_rgb[G] + src_rgb1[G] + 1) >> 1;                    \
+      uint8_t ar = (src_rgb[R] + src_rgb1[R] + 1) >> 1;                    \
+      dst_u[0] = RGBToU(ar, ag, ab);                                       \
+      dst_v[0] = RGBToV(ar, ag, ab);                                       \
     }                                                                      \
   }
 #endif
@@ -762,62 +727,37 @@
 MAKEROWY(RAW, 0, 1, 2, 3)
 #undef MAKEROWY
 
-// JPeg uses a variation on BT.601-1 full range
+// JPeg uses BT.601-1 full range
 // y =  0.29900 * r + 0.58700 * g + 0.11400 * b
 // u = -0.16874 * r - 0.33126 * g + 0.50000 * b  + center
 // v =  0.50000 * r - 0.41869 * g - 0.08131 * b  + center
-// BT.601 Mpeg range uses:
-// b 0.1016 * 255 = 25.908 = 25
-// g 0.5078 * 255 = 129.489 = 129
-// r 0.2578 * 255 = 65.739 = 66
-// JPeg 7 bit Y (deprecated)
-// b 0.11400 * 128 = 14.592 = 15
-// g 0.58700 * 128 = 75.136 = 75
-// r 0.29900 * 128 = 38.272 = 38
 // JPeg 8 bit Y:
 // b 0.11400 * 256 = 29.184 = 29
 // g 0.58700 * 256 = 150.272 = 150
 // r 0.29900 * 256 = 76.544 = 77
 // JPeg 8 bit U:
-// b  0.50000 * 255 = 127.5 = 127
-// g -0.33126 * 255 = -84.4713 = -84
-// r -0.16874 * 255 = -43.0287 = -43
+// b  0.50000 * 256 = 128.0 = 128
+// g -0.33126 * 256 = −84.80256 = -85
+// r -0.16874 * 256 = −43.19744 = -43
 // JPeg 8 bit V:
-// b -0.08131 * 255 = -20.73405 = -20
-// g -0.41869 * 255 = -106.76595 = -107
-// r  0.50000 * 255 = 127.5 = 127
+// b -0.08131 * 256 = −20.81536 = -21
+// g -0.41869 * 256 = −107.18464 = -107
+// r  0.50000 * 256 = 128.0 = 128
 
-#ifdef LIBYUV_RGB7
-// Old 7 bit math for compatibility on unsupported platforms.
-static __inline uint8_t RGBToYJ(uint8_t r, uint8_t g, uint8_t b) {
-  return (38 * r + 75 * g + 15 * b + 64) >> 7;
-}
-#else
 // 8 bit
 static __inline uint8_t RGBToYJ(uint8_t r, uint8_t g, uint8_t b) {
   return (77 * r + 150 * g + 29 * b + 128) >> 8;
 }
-#endif
-
-#if defined(LIBYUV_ARGBTOUV_PAVGB)
 static __inline uint8_t RGBToUJ(uint8_t r, uint8_t g, uint8_t b) {
-  return (127 * b - 84 * g - 43 * r + 0x8080) >> 8;
+  return (128 * b - 85 * g - 43 * r + 0x8000) >> 8;
 }
 static __inline uint8_t RGBToVJ(uint8_t r, uint8_t g, uint8_t b) {
-  return (127 * r - 107 * g - 20 * b + 0x8080) >> 8;
+  return (128 * r - 107 * g - 21 * b + 0x8000) >> 8;
 }
-#else
-static __inline uint8_t RGB2xToUJ(uint16_t r, uint16_t g, uint16_t b) {
-  return ((127 / 2) * b - (84 / 2) * g - (43 / 2) * r + 0x8080) >> 8;
-}
-static __inline uint8_t RGB2xToVJ(uint16_t r, uint16_t g, uint16_t b) {
-  return ((127 / 2) * r - (107 / 2) * g - (20 / 2) * b + 0x8080) >> 8;
-}
-#endif
 
 // ARGBToYJ_C and ARGBToUVJ_C
 // Intel version mimic SSE/AVX which does 2 pavgb
-#if LIBYUV_ARGBTOUV_PAVGB
+#if defined(LIBYUV_ARGBTOUV_PAVGB)
 #define MAKEROWYJ(NAME, R, G, B, BPP)                                       \
   void NAME##ToYJRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width) { \
     int x;                                                                  \
@@ -854,7 +794,7 @@
     }                                                                       \
   }
 #else
-// ARM version does sum / 2 then multiply by 2x smaller coefficients
+// ARM version does average of 4 pixels with rounding
 #define MAKEROWYJ(NAME, R, G, B, BPP)                                       \
   void NAME##ToYJRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width) { \
     int x;                                                                  \
@@ -869,28 +809,28 @@
     const uint8_t* src_rgb1 = src_rgb + src_stride_rgb;                     \
     int x;                                                                  \
     for (x = 0; x < width - 1; x += 2) {                                    \
-      uint16_t ab = (src_rgb[B] + src_rgb[B + BPP] + src_rgb1[B] +          \
-                     src_rgb1[B + BPP] + 1) >>                              \
-                    1;                                                      \
-      uint16_t ag = (src_rgb[G] + src_rgb[G + BPP] + src_rgb1[G] +          \
-                     src_rgb1[G + BPP] + 1) >>                              \
-                    1;                                                      \
-      uint16_t ar = (src_rgb[R] + src_rgb[R + BPP] + src_rgb1[R] +          \
-                     src_rgb1[R + BPP] + 1) >>                              \
-                    1;                                                      \
-      dst_u[0] = RGB2xToUJ(ar, ag, ab);                                     \
-      dst_v[0] = RGB2xToVJ(ar, ag, ab);                                     \
+      uint8_t ab = (src_rgb[B] + src_rgb[B + BPP] + src_rgb1[B] +           \
+                    src_rgb1[B + BPP] + 2) >>                               \
+                   2;                                                       \
+      uint8_t ag = (src_rgb[G] + src_rgb[G + BPP] + src_rgb1[G] +           \
+                    src_rgb1[G + BPP] + 2) >>                               \
+                   2;                                                       \
+      uint8_t ar = (src_rgb[R] + src_rgb[R + BPP] + src_rgb1[R] +           \
+                    src_rgb1[R + BPP] + 2) >>                               \
+                   2;                                                       \
+      dst_u[0] = RGBToUJ(ar, ag, ab);                                       \
+      dst_v[0] = RGBToVJ(ar, ag, ab);                                       \
       src_rgb += BPP * 2;                                                   \
       src_rgb1 += BPP * 2;                                                  \
       dst_u += 1;                                                           \
       dst_v += 1;                                                           \
     }                                                                       \
     if (width & 1) {                                                        \
-      uint16_t ab = (src_rgb[B] + src_rgb1[B]);                             \
-      uint16_t ag = (src_rgb[G] + src_rgb1[G]);                             \
-      uint16_t ar = (src_rgb[R] + src_rgb1[R]);                             \
-      dst_u[0] = RGB2xToUJ(ar, ag, ab);                                     \
-      dst_v[0] = RGB2xToVJ(ar, ag, ab);                                     \
+      uint16_t ab = (src_rgb[B] + src_rgb1[B] + 1) >> 1;                    \
+      uint16_t ag = (src_rgb[G] + src_rgb1[G] + 1) >> 1;                    \
+      uint16_t ar = (src_rgb[R] + src_rgb1[R] + 1) >> 1;                    \
+      dst_u[0] = RGBToUJ(ar, ag, ab);                                       \
+      dst_v[0] = RGBToVJ(ar, ag, ab);                                       \
     }                                                                       \
   }
 
@@ -988,18 +928,18 @@
     g3 = STATIC_CAST(uint8_t, (g3 << 2) | (g3 >> 4));
     r3 = STATIC_CAST(uint8_t, (r3 << 3) | (r3 >> 2));
 
-#if LIBYUV_ARGBTOUV_PAVGB
+#if defined(LIBYUV_ARGBTOUV_PAVGB)
     uint8_t ab = AVGB(AVGB(b0, b2), AVGB(b1, b3));
     uint8_t ag = AVGB(AVGB(g0, g2), AVGB(g1, g3));
     uint8_t ar = AVGB(AVGB(r0, r2), AVGB(r1, r3));
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
 #else
-    uint16_t b = (b0 + b1 + b2 + b3 + 1) >> 1;
-    uint16_t g = (g0 + g1 + g2 + g3 + 1) >> 1;
-    uint16_t r = (r0 + r1 + r2 + r3 + 1) >> 1;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
+    uint8_t b = (b0 + b1 + b2 + b3 + 2) >> 2;
+    uint8_t g = (g0 + g1 + g2 + g3 + 2) >> 2;
+    uint8_t r = (r0 + r1 + r2 + r3 + 2) >> 2;
+    dst_u[0] = RGBToU(r, g, b);
+    dst_v[0] = RGBToV(r, g, b);
 #endif
 
     src_rgb565 += 4;
@@ -1023,19 +963,11 @@
     g2 = STATIC_CAST(uint8_t, (g2 << 2) | (g2 >> 4));
     r2 = STATIC_CAST(uint8_t, (r2 << 3) | (r2 >> 2));
 
-#if LIBYUV_ARGBTOUV_PAVGB
     uint8_t ab = AVGB(b0, b2);
     uint8_t ag = AVGB(g0, g2);
     uint8_t ar = AVGB(r0, r2);
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
-#else
-    uint16_t b = b0 + b2;
-    uint16_t g = g0 + g2;
-    uint16_t r = r0 + r2;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
-#endif
   }
 }
 
@@ -1077,18 +1009,18 @@
     g3 = STATIC_CAST(uint8_t, (g3 << 3) | (g3 >> 2));
     r3 = STATIC_CAST(uint8_t, (r3 << 3) | (r3 >> 2));
 
-#if LIBYUV_ARGBTOUV_PAVGB
+#if defined(LIBYUV_ARGBTOUV_PAVGB)
     uint8_t ab = AVGB(AVGB(b0, b2), AVGB(b1, b3));
     uint8_t ag = AVGB(AVGB(g0, g2), AVGB(g1, g3));
     uint8_t ar = AVGB(AVGB(r0, r2), AVGB(r1, r3));
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
 #else
-    uint16_t b = (b0 + b1 + b2 + b3 + 1) >> 1;
-    uint16_t g = (g0 + g1 + g2 + g3 + 1) >> 1;
-    uint16_t r = (r0 + r1 + r2 + r3 + 1) >> 1;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
+    uint8_t b = (b0 + b1 + b2 + b3 + 2) >> 2;
+    uint8_t g = (g0 + g1 + g2 + g3 + 2) >> 2;
+    uint8_t r = (r0 + r1 + r2 + r3 + 2) >> 2;
+    dst_u[0] = RGBToU(r, g, b);
+    dst_v[0] = RGBToV(r, g, b);
 #endif
 
     src_argb1555 += 4;
@@ -1113,19 +1045,11 @@
     g2 = STATIC_CAST(uint8_t, (g2 << 3) | (g2 >> 2));
     r2 = STATIC_CAST(uint8_t, (r2 << 3) | (r2 >> 2));
 
-#if LIBYUV_ARGBTOUV_PAVGB
     uint8_t ab = AVGB(b0, b2);
     uint8_t ag = AVGB(g0, g2);
     uint8_t ar = AVGB(r0, r2);
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
-#else
-    uint16_t b = b0 + b2;
-    uint16_t g = g0 + g2;
-    uint16_t r = r0 + r2;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
-#endif
   }
 }
 
@@ -1163,18 +1087,18 @@
     g3 = STATIC_CAST(uint8_t, (g3 << 4) | g3);
     r3 = STATIC_CAST(uint8_t, (r3 << 4) | r3);
 
-#if LIBYUV_ARGBTOUV_PAVGB
+#if defined(LIBYUV_ARGBTOUV_PAVGB)
     uint8_t ab = AVGB(AVGB(b0, b2), AVGB(b1, b3));
     uint8_t ag = AVGB(AVGB(g0, g2), AVGB(g1, g3));
     uint8_t ar = AVGB(AVGB(r0, r2), AVGB(r1, r3));
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
 #else
-    uint16_t b = (b0 + b1 + b2 + b3 + 1) >> 1;
-    uint16_t g = (g0 + g1 + g2 + g3 + 1) >> 1;
-    uint16_t r = (r0 + r1 + r2 + r3 + 1) >> 1;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
+    uint8_t b = (b0 + b1 + b2 + b3 + 2) >> 2;
+    uint8_t g = (g0 + g1 + g2 + g3 + 2) >> 2;
+    uint8_t r = (r0 + r1 + r2 + r3 + 2) >> 2;
+    dst_u[0] = RGBToU(r, g, b);
+    dst_v[0] = RGBToV(r, g, b);
 #endif
 
     src_argb4444 += 4;
@@ -1197,19 +1121,11 @@
     g2 = STATIC_CAST(uint8_t, (g2 << 4) | g2);
     r2 = STATIC_CAST(uint8_t, (r2 << 4) | r2);
 
-#if LIBYUV_ARGBTOUV_PAVGB
     uint8_t ab = AVGB(b0, b2);
     uint8_t ag = AVGB(g0, g2);
     uint8_t ar = AVGB(r0, r2);
     dst_u[0] = RGBToU(ar, ag, ab);
     dst_v[0] = RGBToV(ar, ag, ab);
-#else
-    uint16_t b = b0 + b2;
-    uint16_t g = g0 + g2;
-    uint16_t r = r0 + r2;
-    dst_u[0] = RGB2xToU(r, g, b);
-    dst_v[0] = RGB2xToV(r, g, b);
-#endif
   }
 }
 
@@ -1230,6 +1146,23 @@
   }
 }
 
+void ARGBToUVJ444Row_C(const uint8_t* src_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  int x;
+  for (x = 0; x < width; ++x) {
+    uint8_t ab = src_argb[0];
+    uint8_t ag = src_argb[1];
+    uint8_t ar = src_argb[2];
+    dst_u[0] = RGBToUJ(ar, ag, ab);
+    dst_v[0] = RGBToVJ(ar, ag, ab);
+    src_argb += 4;
+    dst_u += 1;
+    dst_v += 1;
+  }
+}
+
 void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width) {
   int x;
   for (x = 0; x < width; ++x) {
@@ -1375,34 +1308,29 @@
 #undef REPEAT8
 #undef SHADE
 
-#define REPEAT8(v) (v) | ((v) << 8)
-#define SHADE(f, v) v* f >> 16
-
 void ARGBMultiplyRow_C(const uint8_t* src_argb,
                        const uint8_t* src_argb1,
                        uint8_t* dst_argb,
                        int width) {
   int i;
   for (i = 0; i < width; ++i) {
-    const uint32_t b = REPEAT8(src_argb[0]);
-    const uint32_t g = REPEAT8(src_argb[1]);
-    const uint32_t r = REPEAT8(src_argb[2]);
-    const uint32_t a = REPEAT8(src_argb[3]);
+    const uint32_t b = src_argb[0];
+    const uint32_t g = src_argb[1];
+    const uint32_t r = src_argb[2];
+    const uint32_t a = src_argb[3];
     const uint32_t b_scale = src_argb1[0];
     const uint32_t g_scale = src_argb1[1];
     const uint32_t r_scale = src_argb1[2];
     const uint32_t a_scale = src_argb1[3];
-    dst_argb[0] = STATIC_CAST(uint8_t, SHADE(b, b_scale));
-    dst_argb[1] = STATIC_CAST(uint8_t, SHADE(g, g_scale));
-    dst_argb[2] = STATIC_CAST(uint8_t, SHADE(r, r_scale));
-    dst_argb[3] = STATIC_CAST(uint8_t, SHADE(a, a_scale));
+    dst_argb[0] = STATIC_CAST(uint8_t, (b * b_scale + 128) >> 8);
+    dst_argb[1] = STATIC_CAST(uint8_t, (g * g_scale + 128) >> 8);
+    dst_argb[2] = STATIC_CAST(uint8_t, (r * r_scale + 128) >> 8);
+    dst_argb[3] = STATIC_CAST(uint8_t, (a * a_scale + 128) >> 8);
     src_argb += 4;
     src_argb1 += 4;
     dst_argb += 4;
   }
 }
-#undef REPEAT8
-#undef SHADE
 
 #define SHADE(f, v) clamp255(v + f)
 
@@ -3245,6 +3173,24 @@
   }
 }
 
+// Use scale to convert J420 to I420
+// scale parameter is 8.8 fixed point but limited to 0 to 255
+// Function is based on DivideRow, but adds a bias
+// Does not clamp
+void Convert8To8Row_C(const uint8_t* src_y,
+                      uint8_t* dst_y,
+                      int scale,
+                      int bias,
+                      int width) {
+  int x;
+  assert(scale >= 0);
+  assert(scale <= 255);
+
+  for (x = 0; x < width; ++x) {
+    dst_y[x] = ((src_y[x] * scale) >> 8) + bias;
+  }
+}
+
 void CopyRow_C(const uint8_t* src, uint8_t* dst, int count) {
   memcpy(dst, src, count);
 }
@@ -3535,7 +3481,7 @@
     T(0xfc),    T(0xfd),    T(0xfe), 0x01000100};
 #undef T
 
-#if LIBYUV_UNATTENUATE_DUP
+#if defined(LIBYUV_UNATTENUATE_DUP)
 // This code mimics the Intel SIMD version for better testability.
 #define UNATTENUATE(f, ia) clamp255(((f | (f << 8)) * ia) >> 16)
 #else
@@ -4008,7 +3954,7 @@
 #define MAXTWIDTH 2048
 
 #if !(defined(_MSC_VER) && !defined(__clang__) && defined(_M_IX86)) && \
-    defined(HAS_I422TORGB565ROW_SSSE3)
+    defined(HAS_I422TORGB565ROW_SSSE3) && !defined(LIBYUV_ENABLE_ROWWIN)
 // row_win.cc has asm version, but GCC uses 2 step wrapper.
 void I422ToRGB565Row_SSSE3(const uint8_t* src_y,
                            const uint8_t* src_u,
@@ -4352,13 +4298,17 @@
 #endif  // HAS_RGB24TOYJROW_AVX2
 
 #ifdef HAS_RAWTOYJROW_AVX2
-// Convert 16 RAW pixels (64 bytes) to 16 YJ values.
+// Convert 32 RAW pixels (128 bytes) to 32 YJ values.
 void RAWToYJRow_AVX2(const uint8_t* src_raw, uint8_t* dst_yj, int width) {
   // Row buffer for intermediate ARGB pixels.
   SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]);
   while (width > 0) {
     int twidth = width > MAXTWIDTH ? MAXTWIDTH : width;
+#ifdef HAS_RAWTOARGBROW_AVX2
+    RAWToARGBRow_AVX2(src_raw, row, twidth);
+#else
     RAWToARGBRow_SSSE3(src_raw, row, twidth);
+#endif
     ARGBToYJRow_AVX2(row, dst_yj, twidth);
     src_raw += twidth * 3;
     dst_yj += twidth;
diff --git a/source/row_gcc.cc b/source/row_gcc.cc
index d807498..8f79803 100644
--- a/source/row_gcc.cc
+++ b/source/row_gcc.cc
@@ -15,7 +15,9 @@
 #endif
 
 // This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 
 #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3)
 
@@ -35,60 +37,25 @@
 #endif  // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3)
 
 #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3)
-
-static const vec8 kARGBToU = {112, -74, -38, 0, 112, -74, -38, 0,
-                              112, -74, -38, 0, 112, -74, -38, 0};
-
-static const vec8 kARGBToUJ = {127, -84, -43, 0, 127, -84, -43, 0,
-                               127, -84, -43, 0, 127, -84, -43, 0};
-
-static const vec8 kABGRToUJ = {-43, -84, 127, 0, -43, -84, 127, 0,
-                               -43, -84, 127, 0, -43, -84, 127, 0};
-
-static const vec8 kARGBToV = {-18, -94, 112, 0, -18, -94, 112, 0,
-                              -18, -94, 112, 0, -18, -94, 112, 0};
-
-static const vec8 kARGBToVJ = {-20, -107, 127, 0, -20, -107, 127, 0,
-                               -20, -107, 127, 0, -20, -107, 127, 0};
-
-static const vec8 kABGRToVJ = {127, -107, -20, 0, 127, -107, -20, 0,
-                               127, -107, -20, 0, 127, -107, -20, 0};
-
 // Constants for BGRA
 static const uvec8 kBGRAToY = {0u, 66u, 129u, 25u, 0u, 66u, 129u, 25u,
                                0u, 66u, 129u, 25u, 0u, 66u, 129u, 25u};
 
-static const vec8 kBGRAToU = {0, -38, -74, 112, 0, -38, -74, 112,
-                              0, -38, -74, 112, 0, -38, -74, 112};
-
-static const vec8 kBGRAToV = {0, 112, -94, -18, 0, 112, -94, -18,
-                              0, 112, -94, -18, 0, 112, -94, -18};
-
 // Constants for ABGR
 static const uvec8 kABGRToY = {66u, 129u, 25u, 0u, 66u, 129u, 25u, 0u,
                                66u, 129u, 25u, 0u, 66u, 129u, 25u, 0u};
 
-static const vec8 kABGRToU = {-38, -74, 112, 0, -38, -74, 112, 0,
-                              -38, -74, 112, 0, -38, -74, 112, 0};
-
-static const vec8 kABGRToV = {112, -94, -18, 0, 112, -94, -18, 0,
-                              112, -94, -18, 0, 112, -94, -18, 0};
-
 // Constants for RGBA.
 static const uvec8 kRGBAToY = {0u, 25u, 129u, 66u, 0u, 25u, 129u, 66u,
                                0u, 25u, 129u, 66u, 0u, 25u, 129u, 66u};
-
-static const vec8 kRGBAToU = {0, 112, -74, -38, 0, 112, -74, -38,
-                              0, 112, -74, -38, 0, 112, -74, -38};
-
-static const vec8 kRGBAToV = {0, -18, -94, 112, 0, -18, -94, 112,
-                              0, -18, -94, 112, 0, -18, -94, 112};
-
+// 126 (7e) - (-109..110) = 16..235
 static const uvec16 kAddY16 = {0x7e80u, 0x7e80u, 0x7e80u, 0x7e80u,
                                0x7e80u, 0x7e80u, 0x7e80u, 0x7e80u};
+static const uvec16 kAddY0 = {0x8080u, 0x8080u, 0x8080u, 0x8080u,
+                              0x8080u, 0x8080u, 0x8080u, 0x8080u};
 
-static const uvec8 kAddUV128 = {128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u,
-                                128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u};
+static const uvec16 kAddUV128 = {0x8000u, 0x8000u, 0x8000u, 0x8000u,
+                                 0x8000u, 0x8000u, 0x8000u, 0x8000u};
 
 static const uvec16 kSub128 = {0x8080u, 0x8080u, 0x8080u, 0x8080u,
                                0x8080u, 0x8080u, 0x8080u, 0x8080u};
@@ -102,12 +69,16 @@
     0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u};
 
 // Shuffle table for converting RAW to ARGB.
-static const uvec8 kShuffleMaskRAWToARGB = {2u, 1u, 0u, 12u, 5u,  4u,  3u, 13u,
-                                            8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u};
+static const uvec8 kShuffleMaskRAWToARGB = {
+    2u, 1u, 0u, 128u, 5u, 4u, 3u, 128u, 8u, 7u, 6u, 128u, 11u, 10u, 9u, 128u};
+// Shuffle table for converting RAW to ARGB.  Last 12
+static const uvec8 kShuffleMaskRAWToARGB_0 = {6u,  5u,   4u,  128u, 9u,  8u,
+                                              7u,  128u, 12u, 11u,  10u, 128u,
+                                              15u, 14u,  13u, 128u};
 
 // Shuffle table for converting RAW to RGBA.
-static const uvec8 kShuffleMaskRAWToRGBA = {12u, 2u, 1u, 0u, 13u, 5u,  4u,  3u,
-                                            14u, 8u, 7u, 6u, 15u, 11u, 10u, 9u};
+static const uvec8 kShuffleMaskRAWToRGBA = {
+    128u, 2u, 1u, 0u, 128u, 5u, 4u, 3u, 128u, 8u, 7u, 6u, 128u, 11u, 10u, 9u};
 
 // Shuffle table for converting RAW to RGB24.  First 8.
 static const uvec8 kShuffleMaskRAWToRGB24_0 = {
@@ -137,24 +108,20 @@
     0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u};
 
 // YUY2 shuf 16 Y to 32 Y.
-static const lvec8 kShuffleYUY2Y = {0,  0,  2,  2,  4,  4,  6,  6,  8,  8, 10,
-                                    10, 12, 12, 14, 14, 0,  0,  2,  2,  4, 4,
-                                    6,  6,  8,  8,  10, 10, 12, 12, 14, 14};
+static const vec8 kShuffleYUY2Y = {0, 0, 2,  2,  4,  4,  6,  6,
+                                   8, 8, 10, 10, 12, 12, 14, 14};
 
 // YUY2 shuf 8 UV to 16 UV.
-static const lvec8 kShuffleYUY2UV = {1,  3,  1,  3,  5,  7,  5,  7,  9,  11, 9,
-                                     11, 13, 15, 13, 15, 1,  3,  1,  3,  5,  7,
-                                     5,  7,  9,  11, 9,  11, 13, 15, 13, 15};
+static const vec8 kShuffleYUY2UV = {1, 3,  1, 3,  5,  7,  5,  7,
+                                    9, 11, 9, 11, 13, 15, 13, 15};
 
 // UYVY shuf 16 Y to 32 Y.
-static const lvec8 kShuffleUYVYY = {1,  1,  3,  3,  5,  5,  7,  7,  9,  9, 11,
-                                    11, 13, 13, 15, 15, 1,  1,  3,  3,  5, 5,
-                                    7,  7,  9,  9,  11, 11, 13, 13, 15, 15};
+static const vec8 kShuffleUYVYY = {1, 1, 3,  3,  5,  5,  7,  7,
+                                   9, 9, 11, 11, 13, 13, 15, 15};
 
 // UYVY shuf 8 UV to 16 UV.
-static const lvec8 kShuffleUYVYUV = {0,  2,  0,  2,  4,  6,  4,  6,  8,  10, 8,
-                                     10, 12, 14, 12, 14, 0,  2,  0,  2,  4,  6,
-                                     4,  6,  8,  10, 8,  10, 12, 14, 12, 14};
+static const vec8 kShuffleUYVYUV = {0, 2,  0, 2,  4,  6,  4,  6,
+                                    8, 10, 8, 10, 12, 14, 12, 14};
 
 // NV21 shuf 8 VU to 16 UV.
 static const lvec8 kShuffleNV21 = {
@@ -170,7 +137,7 @@
       "pslld       $0x18,%%xmm5                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"
       "lea         0x8(%0),%0                    \n"
       "punpcklbw   %%xmm0,%%xmm0                 \n"
@@ -202,7 +169,7 @@
       "movdqa      %3,%%xmm4                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm3               \n"
@@ -235,40 +202,81 @@
 
 void RAWToARGBRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
   asm volatile(
-      "pcmpeqb     %%xmm5,%%xmm5                 \n"  // 0xff000000
-      "pslld       $0x18,%%xmm5                  \n"
+      "pcmpeqb     %%xmm6,%%xmm6                 \n"  // 0xff000000
+      "pslld       $0x18,%%xmm6                  \n"
       "movdqa      %3,%%xmm4                     \n"
+      "movdqa      %4,%%xmm5                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x20(%0),%%xmm3               \n"
+      "movdqu      12(%0),%%xmm1                 \n"
+      "movdqu      24(%0),%%xmm2                 \n"
+      "movdqu      32(%0),%%xmm3                 \n"
       "lea         0x30(%0),%0                   \n"
-      "movdqa      %%xmm3,%%xmm2                 \n"
-      "palignr     $0x8,%%xmm1,%%xmm2            \n"
-      "pshufb      %%xmm4,%%xmm2                 \n"
-      "por         %%xmm5,%%xmm2                 \n"
-      "palignr     $0xc,%%xmm0,%%xmm1            \n"
       "pshufb      %%xmm4,%%xmm0                 \n"
-      "movdqu      %%xmm2,0x20(%1)               \n"
-      "por         %%xmm5,%%xmm0                 \n"
       "pshufb      %%xmm4,%%xmm1                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "por         %%xmm5,%%xmm1                 \n"
-      "palignr     $0x4,%%xmm3,%%xmm3            \n"
-      "pshufb      %%xmm4,%%xmm3                 \n"
+      "pshufb      %%xmm4,%%xmm2                 \n"
+      "pshufb      %%xmm5,%%xmm3                 \n"
+      "por         %%xmm6,%%xmm0                 \n"
+      "por         %%xmm6,%%xmm1                 \n"
+      "por         %%xmm6,%%xmm2                 \n"
+      "por         %%xmm6,%%xmm3                 \n"
+      "movdqu      %%xmm0,0x00(%1)               \n"
       "movdqu      %%xmm1,0x10(%1)               \n"
-      "por         %%xmm5,%%xmm3                 \n"
+      "movdqu      %%xmm2,0x20(%1)               \n"
       "movdqu      %%xmm3,0x30(%1)               \n"
       "lea         0x40(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      : "+r"(src_raw),              // %0
-        "+r"(dst_argb),             // %1
-        "+r"(width)                 // %2
-      : "m"(kShuffleMaskRAWToARGB)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
+      : "+r"(src_raw),                // %0
+        "+r"(dst_argb),               // %1
+        "+r"(width)                   // %2
+      : "m"(kShuffleMaskRAWToARGB),   // %3
+        "m"(kShuffleMaskRAWToARGB_0)  // %4
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+}
+
+void RAWToARGBRow_AVX2(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
+  asm volatile(
+      "vpcmpeqb    %%ymm6,%%ymm6,%%ymm6          \n"  // 0xff000000
+      "vpslld      $0x18,%%ymm6,%%ymm6           \n"
+      "vbroadcastf128 %3,%%ymm4                  \n"  //
+      "vbroadcastf128 %4,%%ymm5                  \n"  //
+
+      LABELALIGN  //
+      "1:          \n"
+      "vmovdqu     (%0),%%xmm0                   \n"  // first 12
+      "vinserti128 $1,12(%0),%%ymm0,%%ymm0       \n"  // second 12
+      "vmovdqu     24(%0),%%xmm1                 \n"  // third 12
+      "vinserti128 $1,36(%0),%%ymm1,%%ymm1       \n"  // forth 12
+      "vmovdqu     48(%0),%%xmm2                 \n"  // fifth 12
+      "vinserti128 $1,60(%0),%%ymm2,%%ymm2       \n"  // sixth 12
+      "vmovdqu     68(%0),%%xmm3                 \n"  // seventh 12
+      "vinserti128 $1,80(%0),%%ymm3,%%ymm3       \n"  // eighth 12
+      "lea         96(%0),%0                     \n"
+      "vpshufb     %%ymm4,%%ymm0,%%ymm0          \n"
+      "vpshufb     %%ymm4,%%ymm1,%%ymm1          \n"
+      "vpshufb     %%ymm4,%%ymm2,%%ymm2          \n"
+      "vpshufb     %%ymm5,%%ymm3,%%ymm3          \n"
+      "vpor        %%ymm6,%%ymm0,%%ymm0          \n"
+      "vpor        %%ymm6,%%ymm1,%%ymm1          \n"
+      "vpor        %%ymm6,%%ymm2,%%ymm2          \n"
+      "vpor        %%ymm6,%%ymm3,%%ymm3          \n"
+      "vmovdqu     %%ymm0,(%1)                   \n"
+      "vmovdqu     %%ymm1,0x20(%1)               \n"
+      "vmovdqu     %%ymm2,0x40(%1)               \n"
+      "vmovdqu     %%ymm3,0x60(%1)               \n"
+      "lea         0x80(%1),%1                   \n"
+      "sub         $0x20,%2                      \n"
+      "jg          1b                            \n"
+      "vzeroupper  \n"
+      : "+r"(src_raw),                // %0
+        "+r"(dst_argb),               // %1
+        "+r"(width)                   // %2
+      : "m"(kShuffleMaskRAWToARGB),   // %3
+        "m"(kShuffleMaskRAWToARGB_0)  // %4
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
 }
 
 // Same code as RAWToARGB with different shuffler and A in low bits
@@ -279,7 +287,7 @@
       "movdqa      %3,%%xmm4                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm3               \n"
@@ -319,7 +327,7 @@
       "movdqa      %5,%%xmm5                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x4(%0),%%xmm1                \n"
       "movdqu      0x8(%0),%%xmm2                \n"
@@ -361,7 +369,7 @@
       "sub         %0,%1                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "movdqa      %%xmm0,%%xmm2                 \n"
@@ -408,7 +416,7 @@
       "sub         %0,%1                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "movdqa      %%xmm0,%%xmm2                 \n"
@@ -452,7 +460,7 @@
       "sub         %0,%1                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm2                 \n"
       "pand        %%xmm4,%%xmm0                 \n"
@@ -479,81 +487,79 @@
 }
 
 void ARGBToRGB24Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) {
-  asm volatile(
+  asm volatile("movdqa      %3,%%xmm6                     \n"
 
-      "movdqa      %3,%%xmm6                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x30(%0),%%xmm3               \n"
-      "lea         0x40(%0),%0                   \n"
-      "pshufb      %%xmm6,%%xmm0                 \n"
-      "pshufb      %%xmm6,%%xmm1                 \n"
-      "pshufb      %%xmm6,%%xmm2                 \n"
-      "pshufb      %%xmm6,%%xmm3                 \n"
-      "movdqa      %%xmm1,%%xmm4                 \n"
-      "psrldq      $0x4,%%xmm1                   \n"
-      "pslldq      $0xc,%%xmm4                   \n"
-      "movdqa      %%xmm2,%%xmm5                 \n"
-      "por         %%xmm4,%%xmm0                 \n"
-      "pslldq      $0x8,%%xmm5                   \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "por         %%xmm5,%%xmm1                 \n"
-      "psrldq      $0x8,%%xmm2                   \n"
-      "pslldq      $0x4,%%xmm3                   \n"
-      "por         %%xmm3,%%xmm2                 \n"
-      "movdqu      %%xmm1,0x10(%1)               \n"
-      "movdqu      %%xmm2,0x20(%1)               \n"
-      "lea         0x30(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      : "+r"(src),                    // %0
-        "+r"(dst),                    // %1
-        "+r"(width)                   // %2
-      : "m"(kShuffleMaskARGBToRGB24)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x10(%0),%%xmm1               \n"
+               "movdqu      0x20(%0),%%xmm2               \n"
+               "movdqu      0x30(%0),%%xmm3               \n"
+               "lea         0x40(%0),%0                   \n"
+               "pshufb      %%xmm6,%%xmm0                 \n"
+               "pshufb      %%xmm6,%%xmm1                 \n"
+               "pshufb      %%xmm6,%%xmm2                 \n"
+               "pshufb      %%xmm6,%%xmm3                 \n"
+               "movdqa      %%xmm1,%%xmm4                 \n"
+               "psrldq      $0x4,%%xmm1                   \n"
+               "pslldq      $0xc,%%xmm4                   \n"
+               "movdqa      %%xmm2,%%xmm5                 \n"
+               "por         %%xmm4,%%xmm0                 \n"
+               "pslldq      $0x8,%%xmm5                   \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "por         %%xmm5,%%xmm1                 \n"
+               "psrldq      $0x8,%%xmm2                   \n"
+               "pslldq      $0x4,%%xmm3                   \n"
+               "por         %%xmm3,%%xmm2                 \n"
+               "movdqu      %%xmm1,0x10(%1)               \n"
+               "movdqu      %%xmm2,0x20(%1)               \n"
+               "lea         0x30(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               : "+r"(src),                    // %0
+                 "+r"(dst),                    // %1
+                 "+r"(width)                   // %2
+               : "m"(kShuffleMaskARGBToRGB24)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
+                 "xmm6");
 }
 
 void ARGBToRAWRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) {
-  asm volatile(
+  asm volatile("movdqa      %3,%%xmm6                     \n"
 
-      "movdqa      %3,%%xmm6                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x30(%0),%%xmm3               \n"
-      "lea         0x40(%0),%0                   \n"
-      "pshufb      %%xmm6,%%xmm0                 \n"
-      "pshufb      %%xmm6,%%xmm1                 \n"
-      "pshufb      %%xmm6,%%xmm2                 \n"
-      "pshufb      %%xmm6,%%xmm3                 \n"
-      "movdqa      %%xmm1,%%xmm4                 \n"
-      "psrldq      $0x4,%%xmm1                   \n"
-      "pslldq      $0xc,%%xmm4                   \n"
-      "movdqa      %%xmm2,%%xmm5                 \n"
-      "por         %%xmm4,%%xmm0                 \n"
-      "pslldq      $0x8,%%xmm5                   \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "por         %%xmm5,%%xmm1                 \n"
-      "psrldq      $0x8,%%xmm2                   \n"
-      "pslldq      $0x4,%%xmm3                   \n"
-      "por         %%xmm3,%%xmm2                 \n"
-      "movdqu      %%xmm1,0x10(%1)               \n"
-      "movdqu      %%xmm2,0x20(%1)               \n"
-      "lea         0x30(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      : "+r"(src),                  // %0
-        "+r"(dst),                  // %1
-        "+r"(width)                 // %2
-      : "m"(kShuffleMaskARGBToRAW)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x10(%0),%%xmm1               \n"
+               "movdqu      0x20(%0),%%xmm2               \n"
+               "movdqu      0x30(%0),%%xmm3               \n"
+               "lea         0x40(%0),%0                   \n"
+               "pshufb      %%xmm6,%%xmm0                 \n"
+               "pshufb      %%xmm6,%%xmm1                 \n"
+               "pshufb      %%xmm6,%%xmm2                 \n"
+               "pshufb      %%xmm6,%%xmm3                 \n"
+               "movdqa      %%xmm1,%%xmm4                 \n"
+               "psrldq      $0x4,%%xmm1                   \n"
+               "pslldq      $0xc,%%xmm4                   \n"
+               "movdqa      %%xmm2,%%xmm5                 \n"
+               "por         %%xmm4,%%xmm0                 \n"
+               "pslldq      $0x8,%%xmm5                   \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "por         %%xmm5,%%xmm1                 \n"
+               "psrldq      $0x8,%%xmm2                   \n"
+               "pslldq      $0x4,%%xmm3                   \n"
+               "por         %%xmm3,%%xmm2                 \n"
+               "movdqu      %%xmm1,0x10(%1)               \n"
+               "movdqu      %%xmm2,0x20(%1)               \n"
+               "lea         0x30(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               : "+r"(src),                  // %0
+                 "+r"(dst),                  // %1
+                 "+r"(width)                 // %2
+               : "m"(kShuffleMaskARGBToRAW)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
+                 "xmm6");
 }
 
 #ifdef HAS_ARGBTORGB24ROW_AVX2
@@ -566,7 +572,7 @@
       "vmovdqa     %4,%%ymm7                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vmovdqu     0x40(%0),%%ymm2               \n"
@@ -594,7 +600,7 @@
       "lea         0x60(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),                     // %0
         "+r"(dst),                     // %1
         "+r"(width)                    // %2
@@ -627,7 +633,7 @@
       "vmovdqa     %5,%%ymm7                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vmovdqu     0x40(%0),%%ymm2               \n"
@@ -642,7 +648,7 @@
       "lea         0x60(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),                // %0
         "+r"(dst),                // %1
         "+r"(width)               // %2
@@ -660,7 +666,7 @@
       "vmovdqa     %4,%%ymm7                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vmovdqu     0x40(%0),%%ymm2               \n"
@@ -688,7 +694,7 @@
       "lea         0x60(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),                   // %0
         "+r"(dst),                   // %1
         "+r"(width)                  // %2
@@ -710,7 +716,7 @@
       "pslld       $0xb,%%xmm5                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "movdqa      %%xmm0,%%xmm2                 \n"
@@ -755,7 +761,7 @@
       "pslld       $0xb,%%xmm5                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "paddusb     %%xmm6,%%xmm0                 \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
@@ -801,7 +807,7 @@
       "vpslld      $0xb,%%ymm3,%%ymm5            \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vpaddusb    %%ymm6,%%ymm0,%%ymm0          \n"
       "vpsrld      $0x5,%%ymm0,%%ymm2            \n"
@@ -819,7 +825,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),    // %0
         "+r"(dst),    // %1
         "+r"(width)   // %2
@@ -841,7 +847,7 @@
       "pslld       $0xf,%%xmm7                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "movdqa      %%xmm0,%%xmm2                 \n"
@@ -878,7 +884,7 @@
       "psrlw       $0x8,%%xmm3                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "pand        %%xmm3,%%xmm0                 \n"
@@ -946,7 +952,7 @@
       "pshufd      $0x0,%%xmm6,%%xmm6            \n"
       "sub         %0,%1                         \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // fetch 4 ARGB pixels
       "movdqa      %%xmm0,%%xmm1                 \n"
       "pshufb      %%xmm2,%%xmm1                 \n"  // R0B0
@@ -985,7 +991,7 @@
       "pshufd      $0x0,%%xmm6,%%xmm6            \n"
       "sub         %0,%1                         \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // fetch 4 ABGR pixels
       "movdqa      %%xmm0,%%xmm1                 \n"
       "pshufb      %%xmm2,%%xmm1                 \n"  // R0B0
@@ -1021,7 +1027,7 @@
       "vbroadcastss %7,%%ymm6                    \n"  // multipler for AG
       "sub         %0,%1                         \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // fetch 8 ARGB pixels
       "vpshufb     %%ymm2,%%ymm0,%%ymm1          \n"  // R0B0
       "vpand       %%ymm5,%%ymm0,%%ymm0          \n"  // A0G0
@@ -1034,7 +1040,7 @@
       "add         $0x20,%0                      \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
 
       : "+r"(src),          // %0
         "+r"(dst),          // %1
@@ -1058,7 +1064,7 @@
       "vbroadcastss %7,%%ymm6                    \n"  // multipler for AG
       "sub         %0,%1                         \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // fetch 8 ABGR pixels
       "vpshufb     %%ymm2,%%ymm0,%%ymm1          \n"  // R0B0
       "vpand       %%ymm5,%%ymm0,%%ymm0          \n"  // A0G0
@@ -1071,7 +1077,7 @@
       "add         $0x20,%0                      \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
 
       : "+r"(src),          // %0
         "+r"(dst),          // %1
@@ -1097,9 +1103,7 @@
                          uint16_t* dst_ar64,
                          int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "punpcklbw   %%xmm0,%%xmm0                 \n"
@@ -1113,18 +1117,17 @@
       : "+r"(src_argb),  // %0
         "+r"(dst_ar64),  // %1
         "+r"(width)      // %2
-      :
-      : "memory", "cc", "xmm0", "xmm1");
+        ::"memory",
+        "cc", "xmm0", "xmm1");
 }
 
 void ARGBToAB64Row_SSSE3(const uint8_t* src_argb,
                          uint16_t* dst_ab64,
                          int width) {
   asm volatile(
-
       "movdqa      %3,%%xmm2                     \n"
       "movdqa      %4,%%xmm3                     \n" LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "pshufb      %%xmm2,%%xmm0                 \n"
@@ -1147,9 +1150,7 @@
                          uint8_t* dst_argb,
                          int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "psrlw       $8,%%xmm0                     \n"
@@ -1163,33 +1164,33 @@
       : "+r"(src_ar64),  // %0
         "+r"(dst_argb),  // %1
         "+r"(width)      // %2
-      :
-      : "memory", "cc", "xmm0", "xmm1");
+        ::"memory",
+        "cc", "xmm0", "xmm1");
 }
 
 void AB64ToARGBRow_SSSE3(const uint16_t* src_ab64,
                          uint8_t* dst_argb,
                          int width) {
-  asm volatile(
+  asm volatile("movdqa      %3,%%xmm2                     \n"
 
-      "movdqa      %3,%%xmm2                     \n" LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "psrlw       $8,%%xmm0                     \n"
-      "psrlw       $8,%%xmm1                     \n"
-      "packuswb    %%xmm1,%%xmm0                 \n"
-      "pshufb      %%xmm2,%%xmm0                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "lea         0x20(%0),%0                   \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x4,%2                       \n"
-      "jg          1b                            \n"
-      : "+r"(src_ab64),          // %0
-        "+r"(dst_argb),          // %1
-        "+r"(width)              // %2
-      : "m"(kShuffleARGBToABGR)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x10(%0),%%xmm1               \n"
+               "psrlw       $8,%%xmm0                     \n"
+               "psrlw       $8,%%xmm1                     \n"
+               "packuswb    %%xmm1,%%xmm0                 \n"
+               "pshufb      %%xmm2,%%xmm0                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "lea         0x20(%0),%0                   \n"
+               "lea         0x10(%1),%1                   \n"
+               "sub         $0x4,%2                       \n"
+               "jg          1b                            \n"
+               : "+r"(src_ab64),          // %0
+                 "+r"(dst_argb),          // %1
+                 "+r"(width)              // %2
+               : "m"(kShuffleARGBToABGR)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 
 #ifdef HAS_ARGBTOAR64ROW_AVX2
@@ -1197,9 +1198,7 @@
                         uint16_t* dst_ar64,
                         int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
       "vpunpckhbw  %%ymm0,%%ymm0,%%ymm1          \n"
@@ -1210,12 +1209,12 @@
       "lea         0x40(%1),%1                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),  // %0
         "+r"(dst_ar64),  // %1
         "+r"(width)      // %2
-      :
-      : "memory", "cc", "xmm0", "xmm1");
+        ::"memory",
+        "cc", "xmm0", "xmm1");
 }
 #endif
 
@@ -1224,10 +1223,9 @@
                         uint16_t* dst_ab64,
                         int width) {
   asm volatile(
-
       "vbroadcastf128 %3,%%ymm2                  \n"
       "vbroadcastf128 %4,%%ymm3                  \n" LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
       "vpshufb     %%ymm3,%%ymm0,%%ymm1          \n"
@@ -1238,7 +1236,7 @@
       "lea         0x40(%1),%1                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),             // %0
         "+r"(dst_ab64),             // %1
         "+r"(width)                 // %2
@@ -1253,9 +1251,7 @@
                         uint8_t* dst_argb,
                         int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpsrlw      $8,%%ymm0,%%ymm0              \n"
@@ -1267,12 +1263,12 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ar64),  // %0
         "+r"(dst_argb),  // %1
         "+r"(width)      // %2
-      :
-      : "memory", "cc", "xmm0", "xmm1");
+        ::"memory",
+        "cc", "xmm0", "xmm1");
 }
 #endif
 
@@ -1280,28 +1276,26 @@
 void AB64ToARGBRow_AVX2(const uint16_t* src_ab64,
                         uint8_t* dst_argb,
                         int width) {
-  asm volatile(
-
-      "vbroadcastf128 %3,%%ymm2                  \n" LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "vpsrlw      $8,%%ymm0,%%ymm0              \n"
-      "vpsrlw      $8,%%ymm1,%%ymm1              \n"
-      "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"
-      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
-      "vpshufb     %%ymm2,%%ymm0,%%ymm0          \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "lea         0x40(%0),%0                   \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x8,%2                       \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_ab64),          // %0
-        "+r"(dst_argb),          // %1
-        "+r"(width)              // %2
-      : "m"(kShuffleARGBToABGR)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+  asm volatile("vbroadcastf128 %3,%%ymm2                  \n" LABELALIGN
+               "1:          \n"
+               "vmovdqu     (%0),%%ymm0                   \n"
+               "vmovdqu     0x20(%0),%%ymm1               \n"
+               "vpsrlw      $8,%%ymm0,%%ymm0              \n"
+               "vpsrlw      $8,%%ymm1,%%ymm1              \n"
+               "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"
+               "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
+               "vpshufb     %%ymm2,%%ymm0,%%ymm0          \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "lea         0x40(%0),%0                   \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x8,%2                       \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_ab64),          // %0
+                 "+r"(dst_argb),          // %1
+                 "+r"(width)              // %2
+               : "m"(kShuffleARGBToABGR)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif
 
@@ -1359,8 +1353,8 @@
   "vphaddw    %%ymm1,%%ymm0,%%ymm0           \n" /* mutates. */  \
   "vphaddw    %%ymm3,%%ymm2,%%ymm2           \n"                 \
   "prefetcht0 1280(%0)                       \n"                 \
-  "vpaddw     %%" #round ",%%ymm0,%%ymm0     \n" /* Add .5 for rounding. */             \
-  "vpaddw     %%" #round ",%%ymm2,%%ymm2     \n" \
+  "vpaddw     %%" #round ",%%ymm0,%%ymm0     \n" /* Add 16 */    \
+  "vpaddw     %%" #round ",%%ymm2,%%ymm2     \n"                 \
   "vpsrlw     $0x8,%%ymm0,%%ymm0             \n"                 \
   "vpsrlw     $0x8,%%ymm2,%%ymm2             \n"                 \
   "vpackuswb  %%ymm2,%%ymm0,%%ymm0           \n" /* mutates. */  \
@@ -1368,8 +1362,7 @@
   "vmovdqu    %%ymm0,(%1)                    \n"                 \
   "lea       0x20(%1),%1                     \n"                 \
   "sub       $0x20,%2                        \n"                 \
-  "jg        1b                              \n"                 \
-  "vzeroupper                                \n"
+  "jg        1b                              \n"
 
 // clang-format on
 
@@ -1379,9 +1372,10 @@
   asm volatile(
       "movdqa      %3,%%xmm4                     \n"
       "movdqa      %4,%%xmm5                     \n"
-      "movdqa      %5,%%xmm7                     \n"
+      "movdqa      %5,%%xmm7                     \n"  //
 
-      LABELALIGN RGBTOY(xmm7)
+      LABELALIGN ""      //
+      RGBTOY(xmm7)       //
       : "+r"(src_argb),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
@@ -1400,14 +1394,18 @@
   asm volatile(
       "movdqa      %3,%%xmm4                     \n"
       "movdqa      %4,%%xmm5                     \n"
+      "movdqa      %5,%%xmm7                     \n"  //
 
-      LABELALIGN RGBTOY(xmm5)
+      LABELALIGN ""      //
+      RGBTOY(xmm7)       //
       : "+r"(src_argb),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
       : "m"(kARGBToYJ),  // %3
-        "m"(kSub128)     // %4
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+        "m"(kSub128),    // %4
+        "m"(kAddY0)      // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 #endif  // HAS_ARGBTOYJROW_SSSE3
 
@@ -1418,14 +1416,18 @@
   asm volatile(
       "movdqa      %3,%%xmm4                     \n"
       "movdqa      %4,%%xmm5                     \n"
+      "movdqa      %5,%%xmm7                     \n"  //
 
-      LABELALIGN RGBTOY(xmm5)
+      LABELALIGN ""      //
+      RGBTOY(xmm7)       //
       : "+r"(src_abgr),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
       : "m"(kABGRToYJ),  // %3
-        "m"(kSub128)     // %4
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+        "m"(kSub128),    // %4
+        "m"(kAddY0)      // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 #endif  // HAS_ABGRTOYJROW_SSSE3
 
@@ -1436,14 +1438,18 @@
   asm volatile(
       "movdqa      %3,%%xmm4                     \n"
       "movdqa      %4,%%xmm5                     \n"
+      "movdqa      %5,%%xmm7                     \n"  //
 
-      LABELALIGN RGBTOY(xmm5)
+      LABELALIGN ""      //
+      RGBTOY(xmm7)       //
       : "+r"(src_rgba),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
       : "m"(kRGBAToYJ),  // %3
-        "m"(kSub128)     // %4
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+        "m"(kSub128),    // %4
+        "m"(kAddY0)      // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 #endif  // HAS_RGBATOYJROW_SSSE3
 
@@ -1461,8 +1467,11 @@
       "vbroadcastf128 %3,%%ymm4                  \n"
       "vbroadcastf128 %4,%%ymm5                  \n"
       "vbroadcastf128 %5,%%ymm7                  \n"
-      "vmovdqu     %6,%%ymm6                     \n" LABELALIGN RGBTOY_AVX2(
-      ymm7) "vzeroupper                                \n"
+      "vmovdqa     %6,%%ymm6                     \n"  //
+
+      LABELALIGN ""      //
+      RGBTOY_AVX2(ymm7)  //
+      "vzeroupper  \n"
       : "+r"(src_argb),         // %0
         "+r"(dst_y),            // %1
         "+r"(width)             // %2
@@ -1482,8 +1491,11 @@
       "vbroadcastf128 %3,%%ymm4                  \n"
       "vbroadcastf128 %4,%%ymm5                  \n"
       "vbroadcastf128 %5,%%ymm7                  \n"
-      "vmovdqu     %6,%%ymm6                     \n" LABELALIGN RGBTOY_AVX2(
-      ymm7) "vzeroupper                                \n"
+      "vmovdqa     %6,%%ymm6                     \n"  //
+
+      LABELALIGN ""      //
+      RGBTOY_AVX2(ymm7)  //
+      "vzeroupper  \n"
       : "+r"(src_abgr),         // %0
         "+r"(dst_y),            // %1
         "+r"(width)             // %2
@@ -1502,17 +1514,23 @@
   asm volatile(
       "vbroadcastf128 %3,%%ymm4                  \n"
       "vbroadcastf128 %4,%%ymm5                  \n"
-      "vmovdqu     %5,%%ymm6                     \n" LABELALIGN RGBTOY_AVX2(
-      ymm5) "vzeroupper                                \n"
+      "vbroadcastf128 %5,%%ymm7                  \n"
+      "vmovdqa     %6,%%ymm6                     \n"  //
+
+      LABELALIGN ""      //
+      RGBTOY_AVX2(ymm7)  //
+      "vzeroupper  \n"
       : "+r"(src_argb),         // %0
         "+r"(dst_y),            // %1
         "+r"(width)             // %2
       : "m"(kARGBToYJ),         // %3
         "m"(kSub128),           // %4
-        "m"(kPermdARGBToY_AVX)  // %5
+        "m"(kAddY0),            // %5
+        "m"(kPermdARGBToY_AVX)  // %6
       : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
         "xmm7");
 }
+
 #endif  // HAS_ARGBTOYJROW_AVX2
 
 #ifdef HAS_ABGRTOYJROW_AVX2
@@ -1521,14 +1539,19 @@
   asm volatile(
       "vbroadcastf128 %3,%%ymm4                  \n"
       "vbroadcastf128 %4,%%ymm5                  \n"
-      "vmovdqu     %5,%%ymm6                     \n" LABELALIGN RGBTOY_AVX2(
-      ymm5) "vzeroupper                                \n"
+      "vbroadcastf128 %5,%%ymm7                  \n"
+      "vmovdqa     %6,%%ymm6                     \n"  //
+
+      LABELALIGN ""      //
+      RGBTOY_AVX2(ymm7)  //
+      "vzeroupper  \n"
       : "+r"(src_abgr),         // %0
         "+r"(dst_y),            // %1
         "+r"(width)             // %2
       : "m"(kABGRToYJ),         // %3
         "m"(kSub128),           // %4
-        "m"(kPermdARGBToY_AVX)  // %5
+        "m"(kAddY0),            // %5
+        "m"(kPermdARGBToY_AVX)  // %6
       : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
         "xmm7");
 }
@@ -1540,483 +1563,37 @@
   asm volatile(
       "vbroadcastf128 %3,%%ymm4                  \n"
       "vbroadcastf128 %4,%%ymm5                  \n"
-      "vmovdqu     %5,%%ymm6                     \n" LABELALIGN RGBTOY_AVX2(
-      ymm5) "vzeroupper                                \n"
+      "vbroadcastf128 %5,%%ymm7                  \n"
+      "vmovdqa     %6,%%ymm6                     \n"  //
+
+      LABELALIGN ""      //
+      RGBTOY_AVX2(ymm7)  //
+      "vzeroupper  \n"
       : "+r"(src_rgba),         // %0
         "+r"(dst_y),            // %1
         "+r"(width)             // %2
       : "m"(kRGBAToYJ),         // %3
         "m"(kSub128),           // %4
-        "m"(kPermdARGBToY_AVX)  // %5
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+        "m"(kAddY0),            // %5
+        "m"(kPermdARGBToY_AVX)  // %6
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 #endif  // HAS_RGBATOYJROW_AVX2
 
-#ifdef HAS_ARGBTOUVROW_SSSE3
-void ARGBToUVRow_SSSE3(const uint8_t* src_argb,
-                       int src_stride_argb,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
-  asm volatile(
-      "movdqa      %5,%%xmm3                     \n"
-      "movdqa      %6,%%xmm4                     \n"
-      "movdqa      %7,%%xmm5                     \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x10(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm1                 \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x20(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "movdqu      0x30(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm6                 \n"
-
-      "lea         0x40(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm1,%%xmm0           \n"
-      "shufps      $0xdd,%%xmm1,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqa      %%xmm2,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm6,%%xmm2           \n"
-      "shufps      $0xdd,%%xmm6,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
-      "phaddw      %%xmm2,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_argb),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_argb)),  // %4
-        "m"(kARGBToV),                     // %5
-        "m"(kARGBToU),                     // %6
-        "m"(kAddUV128)                     // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
-}
-#endif  // HAS_ARGBTOUVROW_SSSE3
-
-#if defined(HAS_ARGBTOUVROW_AVX2) || defined(HAS_ABGRTOUVROW_AVX2) || \
-    defined(HAS_ARGBTOUVJROW_AVX2) || defined(HAS_ABGRTOUVJROW_AVX2)
-// vpshufb for vphaddw + vpackuswb packed to shorts.
-static const lvec8 kShufARGBToUV_AVX = {
-    0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15,
-    0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15};
-#endif
-
-#if defined(HAS_ARGBTOUVROW_AVX2)
-void ARGBToUVRow_AVX2(const uint8_t* src_argb,
-                      int src_stride_argb,
-                      uint8_t* dst_u,
-                      uint8_t* dst_v,
-                      int width) {
-  asm volatile(
-      "vbroadcastf128 %5,%%ymm5                  \n"
-      "vbroadcastf128 %6,%%ymm6                  \n"
-      "vbroadcastf128 %7,%%ymm7                  \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "vmovdqu     0x40(%0),%%ymm2               \n"
-      "vmovdqu     0x60(%0),%%ymm3               \n"
-      "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
-      "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n"
-      "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n"
-      "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n"
-      "lea         0x80(%0),%0                   \n"
-      "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n"
-      "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n"
-      "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n"
-      "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n"
-
-      "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n"
-      "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n"
-      "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n"
-      "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n"
-      "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n"
-      "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n"
-      "vpsraw      $0x8,%%ymm1,%%ymm1            \n"
-      "vpsraw      $0x8,%%ymm0,%%ymm0            \n"
-      "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n"
-      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
-      "vpshufb     %8,%%ymm0,%%ymm0              \n"
-      "vpaddb      %%ymm5,%%ymm0,%%ymm0          \n"
-
-      "vextractf128 $0x0,%%ymm0,(%1)             \n"
-      "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x20,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_argb),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_argb)),  // %4
-        "m"(kAddUV128),                    // %5
-        "m"(kARGBToV),                     // %6
-        "m"(kARGBToU),                     // %7
-        "m"(kShufARGBToUV_AVX)             // %8
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
-        "xmm7");
-}
-#endif  // HAS_ARGBTOUVROW_AVX2
-
-#ifdef HAS_ABGRTOUVROW_AVX2
-void ABGRToUVRow_AVX2(const uint8_t* src_abgr,
-                      int src_stride_abgr,
-                      uint8_t* dst_u,
-                      uint8_t* dst_v,
-                      int width) {
-  asm volatile(
-      "vbroadcastf128 %5,%%ymm5                  \n"
-      "vbroadcastf128 %6,%%ymm6                  \n"
-      "vbroadcastf128 %7,%%ymm7                  \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "vmovdqu     0x40(%0),%%ymm2               \n"
-      "vmovdqu     0x60(%0),%%ymm3               \n"
-      "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
-      "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n"
-      "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n"
-      "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n"
-      "lea         0x80(%0),%0                   \n"
-      "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n"
-      "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n"
-      "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n"
-      "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n"
-
-      "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n"
-      "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n"
-      "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n"
-      "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n"
-      "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n"
-      "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n"
-      "vpsraw      $0x8,%%ymm1,%%ymm1            \n"
-      "vpsraw      $0x8,%%ymm0,%%ymm0            \n"
-      "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n"
-      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
-      "vpshufb     %8,%%ymm0,%%ymm0              \n"
-      "vpaddb      %%ymm5,%%ymm0,%%ymm0          \n"
-
-      "vextractf128 $0x0,%%ymm0,(%1)             \n"
-      "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x20,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_abgr),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_abgr)),  // %4
-        "m"(kAddUV128),                    // %5
-        "m"(kABGRToV),                     // %6
-        "m"(kABGRToU),                     // %7
-        "m"(kShufARGBToUV_AVX)             // %8
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
-        "xmm7");
-}
-#endif  // HAS_ABGRTOUVROW_AVX2
-
-#ifdef HAS_ARGBTOUVJROW_AVX2
-void ARGBToUVJRow_AVX2(const uint8_t* src_argb,
-                       int src_stride_argb,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
-  asm volatile(
-      "vbroadcastf128 %5,%%ymm5                  \n"
-      "vbroadcastf128 %6,%%ymm6                  \n"
-      "vbroadcastf128 %7,%%ymm7                  \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "vmovdqu     0x40(%0),%%ymm2               \n"
-      "vmovdqu     0x60(%0),%%ymm3               \n"
-      "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
-      "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n"
-      "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n"
-      "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n"
-      "lea         0x80(%0),%0                   \n"
-      "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n"
-      "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n"
-      "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n"
-      "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n"
-
-      "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n"
-      "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n"
-      "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n"
-      "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n"
-      "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n"
-      "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n"
-      "vpaddw      %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpaddw      %%ymm5,%%ymm1,%%ymm1          \n"
-      "vpsraw      $0x8,%%ymm1,%%ymm1            \n"
-      "vpsraw      $0x8,%%ymm0,%%ymm0            \n"
-      "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n"
-      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
-      "vpshufb     %8,%%ymm0,%%ymm0              \n"
-
-      "vextractf128 $0x0,%%ymm0,(%1)             \n"
-      "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x20,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_argb),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_argb)),  // %4
-        "m"(kSub128),                      // %5
-        "m"(kARGBToVJ),                    // %6
-        "m"(kARGBToUJ),                    // %7
-        "m"(kShufARGBToUV_AVX)             // %8
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
-        "xmm7");
-}
-#endif  // HAS_ARGBTOUVJROW_AVX2
-
-// TODO(fbarchard): Pass kABGRToVJ / kABGRToUJ as matrix
-#ifdef HAS_ABGRTOUVJROW_AVX2
-void ABGRToUVJRow_AVX2(const uint8_t* src_abgr,
-                       int src_stride_abgr,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
-  asm volatile(
-      "vbroadcastf128 %5,%%ymm5                  \n"
-      "vbroadcastf128 %6,%%ymm6                  \n"
-      "vbroadcastf128 %7,%%ymm7                  \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "vmovdqu     0x40(%0),%%ymm2               \n"
-      "vmovdqu     0x60(%0),%%ymm3               \n"
-      "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
-      "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n"
-      "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n"
-      "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n"
-      "lea         0x80(%0),%0                   \n"
-      "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n"
-      "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n"
-      "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n"
-      "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n"
-      "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n"
-
-      "vpmaddubsw  %%ymm7,%%ymm0,%%ymm1          \n"
-      "vpmaddubsw  %%ymm7,%%ymm2,%%ymm3          \n"
-      "vpmaddubsw  %%ymm6,%%ymm0,%%ymm0          \n"
-      "vpmaddubsw  %%ymm6,%%ymm2,%%ymm2          \n"
-      "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n"
-      "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n"
-      "vpaddw      %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpaddw      %%ymm5,%%ymm1,%%ymm1          \n"
-      "vpsraw      $0x8,%%ymm1,%%ymm1            \n"
-      "vpsraw      $0x8,%%ymm0,%%ymm0            \n"
-      "vpacksswb   %%ymm0,%%ymm1,%%ymm0          \n"
-      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
-      "vpshufb     %8,%%ymm0,%%ymm0              \n"
-
-      "vextractf128 $0x0,%%ymm0,(%1)             \n"
-      "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x20,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_abgr),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_abgr)),  // %4
-        "m"(kSub128),                      // %5
-        "m"(kABGRToVJ),                    // %6
-        "m"(kABGRToUJ),                    // %7
-        "m"(kShufARGBToUV_AVX)             // %8
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
-        "xmm7");
-}
-#endif  // HAS_ABGRTOUVJROW_AVX2
-
-#ifdef HAS_ARGBTOUVJROW_SSSE3
-void ARGBToUVJRow_SSSE3(const uint8_t* src_argb,
-                        int src_stride_argb,
-                        uint8_t* dst_u,
-                        uint8_t* dst_v,
-                        int width) {
-  asm volatile(
-      "movdqa      %5,%%xmm3                     \n"
-      "movdqa      %6,%%xmm4                     \n"
-      "movdqa      %7,%%xmm5                     \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x10(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm1                 \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x20(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "movdqu      0x30(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm6                 \n"
-
-      "lea         0x40(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm1,%%xmm0           \n"
-      "shufps      $0xdd,%%xmm1,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqa      %%xmm2,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm6,%%xmm2           \n"
-      "shufps      $0xdd,%%xmm6,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
-      "phaddw      %%xmm2,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm1                 \n"
-      "paddw       %%xmm5,%%xmm0                 \n"
-      "paddw       %%xmm5,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_argb),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_argb)),  // %4
-        "m"(kARGBToVJ),                    // %5
-        "m"(kARGBToUJ),                    // %6
-        "m"(kSub128)                       // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
-}
-#endif  // HAS_ARGBTOUVJROW_SSSE3
-
-#ifdef HAS_ABGRTOUVJROW_SSSE3
-void ABGRToUVJRow_SSSE3(const uint8_t* src_abgr,
-                        int src_stride_abgr,
-                        uint8_t* dst_u,
-                        uint8_t* dst_v,
-                        int width) {
-  asm volatile(
-      "movdqa      %5,%%xmm3                     \n"
-      "movdqa      %6,%%xmm4                     \n"
-      "movdqa      %7,%%xmm5                     \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x10(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm1                 \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x20(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "movdqu      0x30(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm6                 \n"
-
-      "lea         0x40(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm1,%%xmm0           \n"
-      "shufps      $0xdd,%%xmm1,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqa      %%xmm2,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm6,%%xmm2           \n"
-      "shufps      $0xdd,%%xmm6,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
-      "phaddw      %%xmm2,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm1                 \n"
-      "paddw       %%xmm5,%%xmm0                 \n"
-      "paddw       %%xmm5,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_abgr),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_abgr)),  // %4
-        "m"(kABGRToVJ),                    // %5
-        "m"(kABGRToUJ),                    // %6
-        "m"(kSub128)                       // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
-}
-#endif  // HAS_ABGRTOUVJROW_SSSE3
-
 #ifdef HAS_ARGBTOUV444ROW_SSSE3
-void ARGBToUV444Row_SSSE3(const uint8_t* src_argb,
-                          uint8_t* dst_u,
-                          uint8_t* dst_v,
-                          int width) {
+
+// Coefficients expressed as negatives to allow 128
+struct RgbUVConstants {
+  vec8 kRGBToU;
+  vec8 kRGBToV;
+};
+
+void ARGBToUV444MatrixRow_SSSE3(const uint8_t* src_argb,
+                                uint8_t* dst_u,
+                                uint8_t* dst_v,
+                                int width,
+                                const struct RgbUVConstants* rgbuvconstants) {
   asm volatile(
       "movdqa      %4,%%xmm3                     \n"
       "movdqa      %5,%%xmm4                     \n"
@@ -2024,22 +1601,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm1                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm4,%%xmm6                 \n"
-      "phaddw      %%xmm1,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm2                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm2                   \n"
-      "packsswb    %%xmm2,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm2               \n"
@@ -2050,48 +1612,198 @@
       "pmaddubsw   %%xmm3,%%xmm6                 \n"
       "phaddw      %%xmm1,%%xmm0                 \n"
       "phaddw      %%xmm6,%%xmm2                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm2                   \n"
-      "packsswb    %%xmm2,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
+      "movdqa      %%xmm5,%%xmm1                 \n"
+      "movdqa      %%xmm5,%%xmm6                 \n"
+      "psubw       %%xmm0,%%xmm1                 \n"
+      "psubw       %%xmm2,%%xmm6                 \n"
+      "psrlw       $0x8,%%xmm1                   \n"
+      "psrlw       $0x8,%%xmm6                   \n"
+      "packuswb    %%xmm6,%%xmm1                 \n"
+      "movdqu      %%xmm1,(%1)                   \n"
+
+      "movdqu      (%0),%%xmm0                   \n"
+      "movdqu      0x10(%0),%%xmm1               \n"
+      "movdqu      0x20(%0),%%xmm2               \n"
+      "movdqu      0x30(%0),%%xmm6               \n"
+      "pmaddubsw   %%xmm4,%%xmm0                 \n"
+      "pmaddubsw   %%xmm4,%%xmm1                 \n"
+      "pmaddubsw   %%xmm4,%%xmm2                 \n"
+      "pmaddubsw   %%xmm4,%%xmm6                 \n"
+      "phaddw      %%xmm1,%%xmm0                 \n"
+      "phaddw      %%xmm6,%%xmm2                 \n"
+      "movdqa      %%xmm5,%%xmm1                 \n"
+      "movdqa      %%xmm5,%%xmm6                 \n"
+      "psubw       %%xmm0,%%xmm1                 \n"
+      "psubw       %%xmm2,%%xmm6                 \n"
+      "psrlw       $0x8,%%xmm1                   \n"
+      "psrlw       $0x8,%%xmm6                   \n"
+      "packuswb    %%xmm6,%%xmm1                 \n"
+      "movdqu      %%xmm1,0x00(%1,%2,1)          \n"
+
       "lea         0x40(%0),%0                   \n"
-      "movdqu      %%xmm0,0x00(%1,%2,1)          \n"
       "lea         0x10(%1),%1                   \n"
       "sub         $0x10,%3                      \n"
       "jg          1b                            \n"
-      : "+r"(src_argb),  // %0
-        "+r"(dst_u),     // %1
-        "+r"(dst_v),     // %2
-        "+rm"(width)     // %3
-      : "m"(kARGBToV),   // %4
-        "m"(kARGBToU),   // %5
-        "m"(kAddUV128)   // %6
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6");
+      : "+r"(src_argb),                // %0
+        "+r"(dst_u),                   // %1
+        "+r"(dst_v),                   // %2
+        "+rm"(width)                   // %3
+      : "m"(rgbuvconstants->kRGBToU),  // %4
+        "m"(rgbuvconstants->kRGBToV),  // %5
+        "m"(kAddUV128)                 // %6
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
 }
 #endif  // HAS_ARGBTOUV444ROW_SSSE3
 
-void BGRAToYRow_SSSE3(const uint8_t* src_bgra, uint8_t* dst_y, int width) {
-  asm volatile(
-      "movdqa      %3,%%xmm4                     \n"
-      "movdqa      %4,%%xmm5                     \n"
-      "movdqa      %5,%%xmm7                     \n"
+#ifdef HAS_ARGBTOUV444ROW_AVX2
 
-      LABELALIGN RGBTOY(xmm7)
-      : "+r"(src_bgra),  // %0
-        "+r"(dst_y),     // %1
-        "+r"(width)      // %2
-      : "m"(kBGRAToY),   // %3
-        "m"(kSub128),    // %4
-        "m"(kAddY16)     // %5
+void ARGBToUV444MatrixRow_AVX2(const uint8_t* src_argb,
+                               uint8_t* dst_u,
+                               uint8_t* dst_v,
+                               int width,
+                               const struct RgbUVConstants* rgbuvconstants) {
+  asm volatile(
+      "vbroadcastf128 %4,%%ymm3                  \n"
+      "vbroadcastf128 %5,%%ymm4                  \n"
+      "vbroadcastf128 %6,%%ymm5                  \n"
+      "vmovdqa     %7,%%ymm7                     \n"
+      "sub         %1,%2                         \n"
+
+      LABELALIGN
+      "1:          \n"
+      "vmovdqu     (%0),%%ymm0                   \n"
+      "vmovdqu     0x20(%0),%%ymm1               \n"
+      "vmovdqu     0x40(%0),%%ymm2               \n"
+      "vmovdqu     0x60(%0),%%ymm6               \n"
+      "vpmaddubsw  %%ymm3,%%ymm0,%%ymm0          \n"
+      "vpmaddubsw  %%ymm3,%%ymm1,%%ymm1          \n"
+      "vpmaddubsw  %%ymm3,%%ymm2,%%ymm2          \n"
+      "vpmaddubsw  %%ymm3,%%ymm6,%%ymm6          \n"
+      "vphaddw     %%ymm1,%%ymm0,%%ymm0          \n"  // mutates
+      "vphaddw     %%ymm6,%%ymm2,%%ymm2          \n"
+      "vpsubw      %%ymm0,%%ymm5,%%ymm0          \n"
+      "vpsubw      %%ymm2,%%ymm5,%%ymm2          \n"
+      "vpsrlw      $0x8,%%ymm0,%%ymm0            \n"
+      "vpsrlw      $0x8,%%ymm2,%%ymm2            \n"
+      "vpackuswb   %%ymm2,%%ymm0,%%ymm0          \n"  // mutates
+      "vpermd      %%ymm0,%%ymm7,%%ymm0          \n"  // unmutate.
+      "vmovdqu     %%ymm0,(%1)                   \n"
+
+      "vmovdqu     (%0),%%ymm0                   \n"
+      "vmovdqu     0x20(%0),%%ymm1               \n"
+      "vmovdqu     0x40(%0),%%ymm2               \n"
+      "vmovdqu     0x60(%0),%%ymm6               \n"
+      "vpmaddubsw  %%ymm4,%%ymm0,%%ymm0          \n"
+      "vpmaddubsw  %%ymm4,%%ymm1,%%ymm1          \n"
+      "vpmaddubsw  %%ymm4,%%ymm2,%%ymm2          \n"
+      "vpmaddubsw  %%ymm4,%%ymm6,%%ymm6          \n"
+      "vphaddw     %%ymm1,%%ymm0,%%ymm0          \n"  // mutates
+      "vphaddw     %%ymm6,%%ymm2,%%ymm2          \n"
+      "vpsubw      %%ymm0,%%ymm5,%%ymm0          \n"
+      "vpsubw      %%ymm2,%%ymm5,%%ymm2          \n"
+      "vpsrlw      $0x8,%%ymm0,%%ymm0            \n"
+      "vpsrlw      $0x8,%%ymm2,%%ymm2            \n"
+      "vpackuswb   %%ymm2,%%ymm0,%%ymm0          \n"  // mutates
+      "vpermd      %%ymm0,%%ymm7,%%ymm0          \n"  // unmutate.
+      "vmovdqu     %%ymm0,(%1,%2,1)              \n"
+      "lea         0x80(%0),%0                   \n"
+      "lea         0x20(%1),%1                   \n"
+      "sub         $0x20,%3                      \n"
+      "jg          1b                            \n"
+      "vzeroupper  \n"
+      : "+r"(src_argb),                // %0
+        "+r"(dst_u),                   // %1
+        "+r"(dst_v),                   // %2
+        "+rm"(width)                   // %3
+      : "m"(rgbuvconstants->kRGBToU),  // %4
+        "m"(rgbuvconstants->kRGBToV),  // %5
+        "m"(kAddUV128),                // %6
+        "m"(kPermdARGBToY_AVX)         // %7
+      : "memory", "cc", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6",
+        "ymm7");
+}
+#endif  // HAS_ARGBTOUV444ROW_AVX2
+
+// vpshufb for vphaddw + vpackuswb packed to shorts.
+static const lvec8 kShufARGBToUV_AVX = {
+    0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15,
+    0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15};
+
+void ARGBToUVMatrixRow_AVX2(const uint8_t* src_argb,
+                            int src_stride_argb,
+                            uint8_t* dst_u,
+                            uint8_t* dst_v,
+                            int width,
+                            const struct RgbUVConstants* rgbuvconstants) {
+  asm volatile(
+      "vbroadcastf128 %5,%%ymm5                  \n"
+      "vbroadcastf128 %6,%%ymm6                  \n"
+      "vbroadcastf128 %7,%%ymm7                  \n"
+      "sub         %1,%2                         \n"
+
+      LABELALIGN
+      "1:          \n"
+      "vmovdqu     (%0),%%ymm0                   \n"
+      "vmovdqu     0x20(%0),%%ymm1               \n"
+      "vmovdqu     0x40(%0),%%ymm2               \n"
+      "vmovdqu     0x60(%0),%%ymm3               \n"
+      "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
+      "vpavgb      0x20(%0,%4,1),%%ymm1,%%ymm1   \n"
+      "vpavgb      0x40(%0,%4,1),%%ymm2,%%ymm2   \n"
+      "vpavgb      0x60(%0,%4,1),%%ymm3,%%ymm3   \n"
+      "lea         0x80(%0),%0                   \n"
+      "vshufps     $0x88,%%ymm1,%%ymm0,%%ymm4    \n"
+      "vshufps     $0xdd,%%ymm1,%%ymm0,%%ymm0    \n"
+      "vpavgb      %%ymm4,%%ymm0,%%ymm0          \n"
+      "vshufps     $0x88,%%ymm3,%%ymm2,%%ymm4    \n"
+      "vshufps     $0xdd,%%ymm3,%%ymm2,%%ymm2    \n"
+      "vpavgb      %%ymm4,%%ymm2,%%ymm2          \n"
+
+      "vpmaddubsw  %%ymm6,%%ymm0,%%ymm1          \n"
+      "vpmaddubsw  %%ymm6,%%ymm2,%%ymm3          \n"
+      "vpmaddubsw  %%ymm7,%%ymm0,%%ymm0          \n"
+      "vpmaddubsw  %%ymm7,%%ymm2,%%ymm2          \n"
+      "vphaddw     %%ymm3,%%ymm1,%%ymm1          \n"
+      "vphaddw     %%ymm2,%%ymm0,%%ymm0          \n"
+      "vpsubw      %%ymm0,%%ymm5,%%ymm0          \n"
+      "vpsubw      %%ymm1,%%ymm5,%%ymm1          \n"
+      "vpsrlw      $0x8,%%ymm1,%%ymm1            \n"
+      "vpsrlw      $0x8,%%ymm0,%%ymm0            \n"
+      "vpackuswb   %%ymm0,%%ymm1,%%ymm0          \n"
+      "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
+      "vpshufb     %8,%%ymm0,%%ymm0              \n"
+
+      "vextractf128 $0x0,%%ymm0,(%1)             \n"
+      "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1)     \n"
+      "lea         0x10(%1),%1                   \n"
+      "subl        $0x20,%3                      \n"
+      "jg          1b                            \n"
+      "vzeroupper  \n"
+      : "+r"(src_argb),  // %0
+        "+r"(dst_u),     // %1
+        "+r"(dst_v),     // %2
+#if defined(__i386__)
+        "+m"(width)  // %3
+#else
+        "+rm"(width)  // %3
+#endif
+      : "r"((intptr_t)(src_stride_argb)),  // %4
+        "m"(kAddUV128),                    // %5
+        "m"(rgbuvconstants->kRGBToU),      // %6
+        "m"(rgbuvconstants->kRGBToV),      // %7
+        "m"(kShufARGBToUV_AVX)             // %8
       : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
         "xmm7");
 }
 
-void BGRAToUVRow_SSSE3(const uint8_t* src_bgra,
-                       int src_stride_bgra,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
+#ifdef HAS_ARGBTOUVROW_SSSE3
+
+void ARGBToUVMatrixRow_SSSE3(const uint8_t* src_argb,
+                             int src_stride_argb,
+                             uint8_t* dst_u,
+                             uint8_t* dst_v,
+                             int width,
+                             const struct RgbUVConstants* rgbuvconstants) {
   asm volatile(
       "movdqa      %5,%%xmm3                     \n"
       "movdqa      %6,%%xmm4                     \n"
@@ -2099,7 +1811,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%4,1),%%xmm7          \n"
       "pavgb       %%xmm7,%%xmm0                 \n"
@@ -2112,7 +1824,6 @@
       "movdqu      0x30(%0),%%xmm6               \n"
       "movdqu      0x30(%0,%4,1),%%xmm7          \n"
       "pavgb       %%xmm7,%%xmm6                 \n"
-
       "lea         0x40(%0),%0                   \n"
       "movdqa      %%xmm0,%%xmm7                 \n"
       "shufps      $0x88,%%xmm1,%%xmm0           \n"
@@ -2122,32 +1833,236 @@
       "shufps      $0x88,%%xmm6,%%xmm2           \n"
       "shufps      $0xdd,%%xmm6,%%xmm7           \n"
       "pavgb       %%xmm7,%%xmm2                 \n"
+
       "movdqa      %%xmm0,%%xmm1                 \n"
       "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
+      "pmaddubsw   %%xmm3,%%xmm0                 \n"
+      "pmaddubsw   %%xmm3,%%xmm2                 \n"
+      "pmaddubsw   %%xmm4,%%xmm1                 \n"
+      "pmaddubsw   %%xmm4,%%xmm6                 \n"
       "phaddw      %%xmm2,%%xmm0                 \n"
       "phaddw      %%xmm6,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
+      "movdqa      %%xmm5,%%xmm2                 \n"
+      "movdqa      %%xmm5,%%xmm6                 \n"
+      "psubw       %%xmm0,%%xmm2                 \n"
+      "psubw       %%xmm1,%%xmm6                 \n"
+      "psrlw       $0x8,%%xmm2                   \n"
+      "psrlw       $0x8,%%xmm6                   \n"
+      "packuswb    %%xmm6,%%xmm2                 \n"
+      "movlps      %%xmm2,(%1)                   \n"
+      "movhps      %%xmm2,0x00(%1,%2,1)          \n"
       "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
+      "subl        $0x10,%3                      \n"
       "jg          1b                            \n"
-      : "+r"(src_bgra),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_bgra)),  // %4
-        "m"(kBGRAToV),                     // %5
-        "m"(kBGRAToU),                     // %6
+      : "+r"(src_argb),  // %0
+        "+r"(dst_u),     // %1
+        "+r"(dst_v),     // %2
+#if defined(__i386__)
+        "+m"(width)  // %3
+#else
+        "+rm"(width)  // %3
+#endif
+      : "r"((intptr_t)(src_stride_argb)),  // %4
+        "m"(rgbuvconstants->kRGBToU),      // %5
+        "m"(rgbuvconstants->kRGBToV),      // %6
         "m"(kAddUV128)                     // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
+}
+
+#endif  // HAS_ARGBTOUVROW_SSSE3
+
+#ifdef HAS_ARGBTOUV444ROW_SSSE3
+
+// RGB to BT601 coefficients
+// UB   0.875 coefficient = 112
+// UG -0.5781 coefficient = -74
+// UR -0.2969 coefficient = -38
+// VB -0.1406 coefficient = -18
+// VG -0.7344 coefficient = -94
+// VR   0.875 coefficient = 112
+
+static const struct RgbUVConstants kARGBI601UVConstants = {
+    {-112, 74, 38, 0, -112, 74, 38, 0, -112, 74, 38, 0, -112, 74, 38, 0},
+    {18, 94, -112, 0, 18, 94, -112, 0, 18, 94, -112, 0, 18, 94, -112, 0}};
+
+void ARGBToUV444Row_SSSE3(const uint8_t* src_argb,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width) {
+  ARGBToUV444MatrixRow_SSSE3(src_argb, dst_u, dst_v, width,
+                             &kARGBI601UVConstants);
+}
+#endif  // HAS_ARGBTOUV444ROW_SSSE3
+
+#ifdef HAS_ARGBTOUV444ROW_AVX2
+void ARGBToUV444Row_AVX2(const uint8_t* src_argb,
+                         uint8_t* dst_u,
+                         uint8_t* dst_v,
+                         int width) {
+  ARGBToUV444MatrixRow_AVX2(src_argb, dst_u, dst_v, width,
+                            &kARGBI601UVConstants);
+}
+#endif  // HAS_ARGBTOUV444ROW_AVX2
+
+#ifdef HAS_ARGBTOUVROW_SSSE3
+void ARGBToUVRow_SSSE3(const uint8_t* src_argb,
+                       int src_stride_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_SSSE3(src_argb, src_stride_argb, dst_u, dst_v, width,
+                          &kARGBI601UVConstants);
+}
+void ARGBToUVRow_AVX2(const uint8_t* src_argb,
+                      int src_stride_argb,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_AVX2(src_argb, src_stride_argb, dst_u, dst_v, width,
+                         &kARGBI601UVConstants);
+}
+
+static const struct RgbUVConstants kABGRI601UVConstants = {
+    {38, 74, -112, 0, 38, 74, -112, 0, 38, 74, -112, 0, 38, 74, -112, 0},
+    {-112, 94, 18, 0, -112, 94, 18, 0, -112, 94, 18, 0, -112, 94, 18, 0}};
+
+void ABGRToUVRow_SSSE3(const uint8_t* src_abgr,
+                       int src_stride_abgr,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_SSSE3(src_abgr, src_stride_abgr, dst_u, dst_v, width,
+                          &kABGRI601UVConstants);
+}
+
+void ABGRToUVRow_AVX2(const uint8_t* src_abgr,
+                      int src_stride_abgr,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_AVX2(src_abgr, src_stride_abgr, dst_u, dst_v, width,
+                         &kABGRI601UVConstants);
+}
+
+static const struct RgbUVConstants kBGRAI601UVConstants = {
+    {0, 38, 74, -112, 0, 38, 74, -112, 0, 38, 74, -112, 0, 38, 74, -112},
+    {0, -112, 94, 18, 0, -112, 94, 18, 0, -112, 94, 18, 0, -112, 94, 18}};
+
+void BGRAToUVRow_SSSE3(const uint8_t* src_bgra,
+                       int src_stride_bgra,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_SSSE3(src_bgra, src_stride_bgra, dst_u, dst_v, width,
+                          &kBGRAI601UVConstants);
+}
+
+static const struct RgbUVConstants kRGBAI601UVConstants = {
+    {0, -112, 74, 38, 0, -112, 74, 38, 0, -112, 74, 38, 0, -112, 74, 38},
+    {0, 18, 94, -112, 0, 18, 94, -112, 0, 18, 94, -112, 0, 18, 94, -112}};
+
+void RGBAToUVRow_SSSE3(const uint8_t* src_rgba,
+                       int src_stride_rgba,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_SSSE3(src_rgba, src_stride_rgba, dst_u, dst_v, width,
+                          &kRGBAI601UVConstants);
+}
+#endif  // HAS_ARGBTOUVROW_SSSE3
+
+#ifdef HAS_ARGBTOUVJ444ROW_SSSE3
+// RGB to JPEG coefficients
+// UB  0.500    coefficient = 128
+// UG -0.33126  coefficient = -85
+// UR -0.16874  coefficient = -43
+// VB -0.08131  coefficient = -21
+// VG -0.41869  coefficient = -107
+// VR 0.500     coefficient = 128
+
+static const struct RgbUVConstants kARGBJPEGUVConstants = {
+    {-128, 85, 43, 0, -128, 85, 43, 0, -128, 85, 43, 0, -128, 85, 43, 0},
+    {21, 107, -128, 0, 21, 107, -128, 0, 21, 107, -128, 0, 21, 107, -128, 0}};
+
+void ARGBToUVJ444Row_SSSE3(const uint8_t* src_argb,
+                           uint8_t* dst_u,
+                           uint8_t* dst_v,
+                           int width) {
+  ARGBToUV444MatrixRow_SSSE3(src_argb, dst_u, dst_v, width,
+                             &kARGBJPEGUVConstants);
+}
+
+#endif  // HAS_ARGBTOUVJ444ROW_SSSE3
+
+#ifdef HAS_ARGBTOUVJ444ROW_AVX2
+void ARGBToUVJ444Row_AVX2(const uint8_t* src_argb,
+                          uint8_t* dst_u,
+                          uint8_t* dst_v,
+                          int width) {
+  ARGBToUV444MatrixRow_AVX2(src_argb, dst_u, dst_v, width,
+                            &kARGBJPEGUVConstants);
+}
+#endif  // HAS_ARGBTOUVJ444ROW_AVX2
+
+void ARGBToUVJRow_AVX2(const uint8_t* src_argb,
+                       int src_stride_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_AVX2(src_argb, src_stride_argb, dst_u, dst_v, width,
+                         &kARGBJPEGUVConstants);
+}
+
+static const struct RgbUVConstants kABGRJPEGUVConstants = {
+    {43, 85, -128, 0, 43, 85, -128, 0, 43, 85, -128, 0, 43, 85, -128, 0},
+    {-128, 107, 21, 0, -128, 107, 21, 0, -128, 107, 21, 0, -128, 107, 21, 0}};
+
+void ABGRToUVJRow_AVX2(const uint8_t* src_abgr,
+                       int src_stride_abgr,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_AVX2(src_abgr, src_stride_abgr, dst_u, dst_v, width,
+                         &kABGRJPEGUVConstants);
+}
+
+#ifdef HAS_ARGBTOUVJROW_SSSE3
+void ARGBToUVJRow_SSSE3(const uint8_t* src_argb,
+                        int src_stride_argb,
+                        uint8_t* dst_u,
+                        uint8_t* dst_v,
+                        int width) {
+  ARGBToUVMatrixRow_SSSE3(src_argb, src_stride_argb, dst_u, dst_v, width,
+                          &kARGBJPEGUVConstants);
+}
+
+void ABGRToUVJRow_SSSE3(const uint8_t* src_abgr,
+                        int src_stride_abgr,
+                        uint8_t* dst_u,
+                        uint8_t* dst_v,
+                        int width) {
+  ARGBToUVMatrixRow_SSSE3(src_abgr, src_stride_abgr, dst_u, dst_v, width,
+                          &kABGRJPEGUVConstants);
+}
+#endif  // HAS_ABGRTOUVJROW_SSSE3
+
+void BGRAToYRow_SSSE3(const uint8_t* src_bgra, uint8_t* dst_y, int width) {
+  asm volatile(
+      "movdqa      %3,%%xmm4                     \n"
+      "movdqa      %4,%%xmm5                     \n"
+      "movdqa      %5,%%xmm7                     \n"
+
+      LABELALIGN ""  //
+      RGBTOY(xmm7)
+      : "+r"(src_bgra),  // %0
+        "+r"(dst_y),     // %1
+        "+r"(width)      // %2
+      : "m"(kBGRAToY),   // %3
+        "m"(kSub128),    // %4
+        "m"(kAddY16)     // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 
 void ABGRToYRow_SSSE3(const uint8_t* src_abgr, uint8_t* dst_y, int width) {
@@ -2156,7 +2071,8 @@
       "movdqa      %4,%%xmm5                     \n"
       "movdqa      %5,%%xmm7                     \n"
 
-      LABELALIGN RGBTOY(xmm7)
+      LABELALIGN ""  //
+      RGBTOY(xmm7)
       : "+r"(src_abgr),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
@@ -2173,7 +2089,8 @@
       "movdqa      %4,%%xmm5                     \n"
       "movdqa      %5,%%xmm7                     \n"
 
-      LABELALIGN RGBTOY(xmm7)
+      LABELALIGN ""  //
+      RGBTOY(xmm7)
       : "+r"(src_rgba),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
@@ -2184,132 +2101,6 @@
         "xmm7");
 }
 
-void ABGRToUVRow_SSSE3(const uint8_t* src_abgr,
-                       int src_stride_abgr,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
-  asm volatile(
-      "movdqa      %5,%%xmm3                     \n"
-      "movdqa      %6,%%xmm4                     \n"
-      "movdqa      %7,%%xmm5                     \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x10(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm1                 \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x20(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "movdqu      0x30(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm6                 \n"
-
-      "lea         0x40(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm1,%%xmm0           \n"
-      "shufps      $0xdd,%%xmm1,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqa      %%xmm2,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm6,%%xmm2           \n"
-      "shufps      $0xdd,%%xmm6,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
-      "phaddw      %%xmm2,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_abgr),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_abgr)),  // %4
-        "m"(kABGRToV),                     // %5
-        "m"(kABGRToU),                     // %6
-        "m"(kAddUV128)                     // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
-}
-
-void RGBAToUVRow_SSSE3(const uint8_t* src_rgba,
-                       int src_stride_rgba,
-                       uint8_t* dst_u,
-                       uint8_t* dst_v,
-                       int width) {
-  asm volatile(
-      "movdqa      %5,%%xmm3                     \n"
-      "movdqa      %6,%%xmm4                     \n"
-      "movdqa      %7,%%xmm5                     \n"
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "movdqu      0x10(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm1                 \n"
-      "movdqu      0x20(%0),%%xmm2               \n"
-      "movdqu      0x20(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqu      0x30(%0),%%xmm6               \n"
-      "movdqu      0x30(%0,%4,1),%%xmm7          \n"
-      "pavgb       %%xmm7,%%xmm6                 \n"
-
-      "lea         0x40(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm1,%%xmm0           \n"
-      "shufps      $0xdd,%%xmm1,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm0                 \n"
-      "movdqa      %%xmm2,%%xmm7                 \n"
-      "shufps      $0x88,%%xmm6,%%xmm2           \n"
-      "shufps      $0xdd,%%xmm6,%%xmm7           \n"
-      "pavgb       %%xmm7,%%xmm2                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm2,%%xmm6                 \n"
-      "pmaddubsw   %%xmm4,%%xmm0                 \n"
-      "pmaddubsw   %%xmm4,%%xmm2                 \n"
-      "pmaddubsw   %%xmm3,%%xmm1                 \n"
-      "pmaddubsw   %%xmm3,%%xmm6                 \n"
-      "phaddw      %%xmm2,%%xmm0                 \n"
-      "phaddw      %%xmm6,%%xmm1                 \n"
-      "psraw       $0x8,%%xmm0                   \n"
-      "psraw       $0x8,%%xmm1                   \n"
-      "packsswb    %%xmm1,%%xmm0                 \n"
-      "paddb       %%xmm5,%%xmm0                 \n"
-      "movlps      %%xmm0,(%1)                   \n"
-      "movhps      %%xmm0,0x00(%1,%2,1)          \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_rgba),                    // %0
-        "+r"(dst_u),                       // %1
-        "+r"(dst_v),                       // %2
-        "+rm"(width)                       // %3
-      : "r"((intptr_t)(src_stride_rgba)),  // %4
-        "m"(kRGBAToV),                     // %5
-        "m"(kRGBAToU),                     // %6
-        "m"(kAddUV128)                     // %7
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7");
-}
-
 #if defined(HAS_I422TOARGBROW_SSSE3) || defined(HAS_I422TOARGBROW_AVX2)
 
 // Read 8 UV from 444
@@ -2467,21 +2258,25 @@
   "punpcklbw  %%xmm4,%%xmm4                                   \n" \
   "lea        0x8(%[y_buf]),%[y_buf]                          \n"
 
-// Read 4 YUY2 with 8 Y and update 4 UV to 8 UV.
+// Read 4 YUY2 with 8 Y and upsample 4 UV to 8 UV.
+// xmm6 kShuffleYUY2Y,
+// xmm7 kShuffleYUY2UV
 #define READYUY2                                                  \
   "movdqu     (%[yuy2_buf]),%%xmm4                            \n" \
-  "pshufb     %[kShuffleYUY2Y], %%xmm4                        \n" \
-  "movdqu     (%[yuy2_buf]),%%xmm3                            \n" \
-  "pshufb     %[kShuffleYUY2UV], %%xmm3                       \n" \
-  "lea        0x10(%[yuy2_buf]),%[yuy2_buf]                   \n"
+  "lea        0x10(%[yuy2_buf]),%[yuy2_buf]                   \n" \
+  "movdqa     %%xmm4,%%xmm3                                   \n" \
+  "pshufb     %%xmm6,%%xmm4                                   \n" \
+  "pshufb     %%xmm7,%%xmm3                                   \n"
 
-// Read 4 UYVY with 8 Y and update 4 UV to 8 UV.
+// Read 4 UYVY with 8 Y and upsample 4 UV to 8 UV.
+// xmm6 kShuffleUYVYY,
+// xmm7 kShuffleUYVYUV
 #define READUYVY                                                  \
   "movdqu     (%[uyvy_buf]),%%xmm4                            \n" \
-  "pshufb     %[kShuffleUYVYY], %%xmm4                        \n" \
-  "movdqu     (%[uyvy_buf]),%%xmm3                            \n" \
-  "pshufb     %[kShuffleUYVYUV], %%xmm3                       \n" \
-  "lea        0x10(%[uyvy_buf]),%[uyvy_buf]                   \n"
+  "lea        0x10(%[uyvy_buf]),%[uyvy_buf]                   \n" \
+  "movdqa     %%xmm4,%%xmm3                                   \n" \
+  "pshufb     %%xmm6,%%xmm4                                   \n" \
+  "pshufb     %%xmm7,%%xmm3                                   \n"
 
 // Read 4 UV from P210, upsample to 8 UV
 #define READP210                                                  \
@@ -2536,6 +2331,7 @@
 
 #else
 #define YUVTORGB_SETUP(yuvconstants)
+
 // Convert 8 pixels: 8 UV and 8 Y
 #define YUVTORGB16(yuvconstants)                                  \
   "pcmpeqb    %%xmm0,%%xmm0                                   \n" \
@@ -2644,7 +2440,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV444
     YUVTORGB(yuvconstants)
     STOREARGB
@@ -2669,33 +2465,26 @@
                                      uint8_t* dst_argb,
                                      const struct YuvConstants* yuvconstants,
                                      int width) {
-  // clang-format off
-  asm volatile (
-  YUVTORGB_SETUP(yuvconstants)
-      "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-  LABELALIGN
-      "1:                                        \n"
-  READYUVA444
-  YUVTORGB(yuvconstants)
-  STOREARGB
-      "subl        $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [u_buf]"+r"(u_buf),    // %[u_buf]
-    [v_buf]"+r"(v_buf),    // %[v_buf]
-    [a_buf]"+r"(a_buf),    // %[a_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA444 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "subl        $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-    [width]"+m"(width)     // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-    [width]"+rm"(width)    // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 #endif  // HAS_I444ALPHATOARGBROW_SSSE3
 
@@ -2712,7 +2501,7 @@
       "sub         %[u_buf],%[v_buf]             \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422
     YUVTORGB(yuvconstants)
     STORERGB24
@@ -2748,7 +2537,7 @@
       "sub         %[u_buf],%[v_buf]             \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV444
     YUVTORGB(yuvconstants)
     STORERGB24
@@ -2783,7 +2572,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422
     YUVTORGB(yuvconstants)
     STOREARGB
@@ -2817,7 +2606,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -2847,7 +2636,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV210
     YUVTORGB(yuvconstants)
     STOREARGB
@@ -2877,7 +2666,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV212
     YUVTORGB(yuvconstants)
     STOREARGB
@@ -2912,7 +2701,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV210
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -2947,7 +2736,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV212
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -2977,7 +2766,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV410
     YUVTORGB(yuvconstants)
     STOREARGB
@@ -3002,27 +2791,26 @@
                                      uint8_t* dst_argb,
                                      const struct YuvConstants* yuvconstants,
                                      int width) {
-  asm volatile(
-      YUVTORGB_SETUP(
-      yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-      LABELALIGN "1:                                        \n" READYUVA210
-          YUVTORGB(yuvconstants) STOREARGB
-      "subl        $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-      : [y_buf] "+r"(y_buf),  // %[y_buf]
-        [u_buf] "+r"(u_buf),  // %[u_buf]
-        [v_buf] "+r"(v_buf),  // %[v_buf]
-        [a_buf] "+r"(a_buf),
-        [dst_argb] "+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA210 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "subl        $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),  // %[y_buf]
+                 [u_buf] "+r"(u_buf),  // %[u_buf]
+                 [v_buf] "+r"(v_buf),  // %[v_buf]
+                 [a_buf] "+r"(a_buf),
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-        [width] "+m"(width)  // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-        [width] "+rm"(width)  // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-      : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-      : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
-        "xmm5");
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 #endif
 
@@ -3035,32 +2823,26 @@
                                      uint8_t* dst_argb,
                                      const struct YuvConstants* yuvconstants,
                                      int width) {
-  // clang-format off
-  asm volatile(
-    YUVTORGB_SETUP(yuvconstants)
-      "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READYUVA410
-    YUVTORGB(yuvconstants)
-    STOREARGB
-      "subl        $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-    : [y_buf] "+r"(y_buf),  // %[y_buf]
-      [u_buf] "+r"(u_buf),  // %[u_buf]
-      [v_buf] "+r"(v_buf),  // %[v_buf]
-      [a_buf] "+r"(a_buf),
-      [dst_argb] "+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA410 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "subl        $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),  // %[y_buf]
+                 [u_buf] "+r"(u_buf),  // %[u_buf]
+                 [v_buf] "+r"(v_buf),  // %[v_buf]
+                 [a_buf] "+r"(a_buf),
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-      [width] "+m"(width)  // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-      [width] "+rm"(width)  // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-    : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-    : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
-      "xmm5");
-  // clang-format on
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 #endif
 
@@ -3082,7 +2864,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV410
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -3107,33 +2889,26 @@
                                      uint8_t* dst_argb,
                                      const struct YuvConstants* yuvconstants,
                                      int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP(yuvconstants)
-      "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READYUVA422
-    YUVTORGB(yuvconstants)
-    STOREARGB
-      "subl        $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [u_buf]"+r"(u_buf),    // %[u_buf]
-    [v_buf]"+r"(v_buf),    // %[v_buf]
-    [a_buf]"+r"(a_buf),    // %[a_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA422 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "subl        $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-    [width]"+m"(width)     // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-    [width]"+rm"(width)    // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS
-    "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 #endif  // HAS_I422ALPHATOARGBROW_SSSE3
 
@@ -3142,27 +2917,20 @@
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP(yuvconstants)
-      "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READNV12
-    YUVTORGB(yuvconstants)
-    STOREARGB
-      "sub         $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [uv_buf]"+r"(uv_buf),    // %[uv_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-    : "memory", "cc", YUVTORGB_REGS
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READNV12 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "sub         $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[uv_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 
 void OMITFP NV21ToARGBRow_SSSE3(const uint8_t* y_buf,
@@ -3170,84 +2938,63 @@
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP(yuvconstants)
-      "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READNV21
-    YUVTORGB(yuvconstants)
-    STOREARGB
-      "sub         $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [vu_buf]"+r"(vu_buf),    // %[vu_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleNV21]"m"(kShuffleNV21)
-    : "memory", "cc", YUVTORGB_REGS
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READNV21 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "sub         $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),               // %[y_buf]
+                 [vu_buf] "+r"(vu_buf),             // %[vu_buf]
+                 [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+                 [width] "+rm"(width)               // %[width]
+               : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+                 [kShuffleNV21] "m"(kShuffleNV21)
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 
 void OMITFP YUY2ToARGBRow_SSSE3(const uint8_t* yuy2_buf,
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP(yuvconstants)
-      "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(
+      "movdqa      %[kShuffleYUY2Y],%%xmm6       \n"
+      "movdqa      %[kShuffleYUY2UV],%%xmm7      \n" YUVTORGB_SETUP(
+          yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READYUY2
-    YUVTORGB(yuvconstants)
-    STOREARGB
+      LABELALIGN "1:          \n" READYUY2 YUVTORGB(yuvconstants) STOREARGB
       "sub         $0x8,%[width]                 \n"
       "jg          1b                            \n"
-  : [yuy2_buf]"+r"(yuy2_buf),    // %[yuy2_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleYUY2Y]"m"(kShuffleYUY2Y),
-    [kShuffleYUY2UV]"m"(kShuffleYUY2UV)
-    : "memory", "cc", YUVTORGB_REGS
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+      : [yuy2_buf] "+r"(yuy2_buf),         // %[yuy2_buf]
+        [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+        [width] "+rm"(width)               // %[width]
+      : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+        [kShuffleYUY2Y] "m"(kShuffleYUY2Y), [kShuffleYUY2UV] "m"(kShuffleYUY2UV)
+      : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
+        "xmm5", "xmm6", "xmm7");
 }
 
 void OMITFP UYVYToARGBRow_SSSE3(const uint8_t* uyvy_buf,
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP(yuvconstants)
-      "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(
+      "movdqa      %[kShuffleUYVYY],%%xmm6       \n"
+      "movdqa      %[kShuffleUYVYUV],%%xmm7      \n" YUVTORGB_SETUP(
+          yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READUYVY
-    YUVTORGB(yuvconstants)
-    STOREARGB
+      LABELALIGN "1:          \n" READUYVY YUVTORGB(yuvconstants) STOREARGB
       "sub         $0x8,%[width]                 \n"
       "jg          1b                            \n"
-  : [uyvy_buf]"+r"(uyvy_buf),    // %[uyvy_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleUYVYY]"m"(kShuffleUYVYY),
-    [kShuffleUYVYUV]"m"(kShuffleUYVYUV)
-    : "memory", "cc", YUVTORGB_REGS
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+      : [uyvy_buf] "+r"(uyvy_buf),         // %[uyvy_buf]
+        [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+        [width] "+rm"(width)               // %[width]
+      : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+        [kShuffleUYVYY] "m"(kShuffleUYVYY), [kShuffleUYVYUV] "m"(kShuffleUYVYUV)
+      : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
+        "xmm5");
 }
 
 void OMITFP P210ToARGBRow_SSSE3(const uint16_t* y_buf,
@@ -3255,21 +3002,20 @@
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  asm volatile(
-      YUVTORGB_SETUP(
-      yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-      LABELALIGN "1:                                        \n" READP210
-          YUVTORGB(yuvconstants) STOREARGB
-      "sub         $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-      : [y_buf] "+r"(y_buf),              // %[y_buf]
-        [uv_buf] "+r"(uv_buf),            // %[u_buf]
-        [dst_argb] "+r"(dst_argb),        // %[dst_argb]
-        [width] "+rm"(width)              // %[width]
-      : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-      : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
-        "xmm5");
+               LABELALIGN "1:          \n" READP210 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "sub         $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[u_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 
 void OMITFP P410ToARGBRow_SSSE3(const uint16_t* y_buf,
@@ -3277,21 +3023,20 @@
                                 uint8_t* dst_argb,
                                 const struct YuvConstants* yuvconstants,
                                 int width) {
-  asm volatile(
-      YUVTORGB_SETUP(
-      yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
+  asm volatile(YUVTORGB_SETUP(
+                   yuvconstants) "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
-      LABELALIGN "1:                                        \n" READP410
-          YUVTORGB(yuvconstants) STOREARGB
-      "sub         $0x8,%[width]                 \n"
-      "jg          1b                            \n"
-      : [y_buf] "+r"(y_buf),              // %[y_buf]
-        [uv_buf] "+r"(uv_buf),            // %[u_buf]
-        [dst_argb] "+r"(dst_argb),        // %[dst_argb]
-        [width] "+rm"(width)              // %[width]
-      : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-      : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3", "xmm4",
-        "xmm5");
+               LABELALIGN "1:          \n" READP410 YUVTORGB(yuvconstants)
+                   STOREARGB
+               "sub         $0x8,%[width]                 \n"
+               "jg          1b                            \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[u_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS "xmm0", "xmm1", "xmm2", "xmm3",
+                 "xmm4", "xmm5");
 }
 
 void OMITFP P210ToAR30Row_SSSE3(const uint16_t* y_buf,
@@ -3309,7 +3054,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READP210
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -3340,7 +3085,7 @@
       "psrlw       $6,%%xmm7                     \n"  // 1023 for max
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READP410
     YUVTORGB16(yuvconstants)
     STOREAR30
@@ -3368,7 +3113,7 @@
       "pcmpeqb     %%xmm5,%%xmm5                 \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422
     YUVTORGB(yuvconstants)
     STORERGBA
@@ -3422,7 +3167,7 @@
   "vpunpcklbw %%zmm1,%%zmm3,%%zmm3                                \n" \
   "vpermq     $0xd8,%%zmm3,%%zmm3                                 \n" \
   "vpunpcklwd %%zmm3,%%zmm3,%%zmm3                                \n" \
-  "vmovdqu8   (%[y_buf]),%%ymm4                                   \n" \
+  "vmovups    (%[y_buf]),%%ymm4                                   \n" \
   "vpermq     %%zmm4,%%zmm17,%%zmm4                               \n" \
   "vpermq     $0xd8,%%zmm4,%%zmm4                                 \n" \
   "vpunpcklbw %%zmm4,%%zmm4,%%zmm4                                \n" \
@@ -3598,19 +3343,21 @@
   "lea        0x20(%[y_buf]),%[y_buf]                             \n"
 
 // Read 8 YUY2 with 16 Y and upsample 8 UV to 16 UV.
+// ymm6 kShuffleYUY2Y,
+// ymm7 kShuffleYUY2UV
 #define READYUY2_AVX2                                                 \
-  "vmovdqu    (%[yuy2_buf]),%%ymm4                                \n" \
-  "vpshufb    %[kShuffleYUY2Y], %%ymm4, %%ymm4                    \n" \
-  "vmovdqu    (%[yuy2_buf]),%%ymm3                                \n" \
-  "vpshufb    %[kShuffleYUY2UV], %%ymm3, %%ymm3                   \n" \
+  "vmovdqu    (%[yuy2_buf]),%%ymm1                                \n" \
+  "vpshufb    %%ymm6,%%ymm1,%%ymm4                                \n" \
+  "vpshufb    %%ymm7,%%ymm1,%%ymm3                                \n" \
   "lea        0x20(%[yuy2_buf]),%[yuy2_buf]                       \n"
 
 // Read 8 UYVY with 16 Y and upsample 8 UV to 16 UV.
+// ymm6 kShuffleUYVYY,
+// ymm7 kShuffleUYVYUV
 #define READUYVY_AVX2                                                 \
-  "vmovdqu    (%[uyvy_buf]),%%ymm4                                \n" \
-  "vpshufb    %[kShuffleUYVYY], %%ymm4, %%ymm4                    \n" \
-  "vmovdqu    (%[uyvy_buf]),%%ymm3                                \n" \
-  "vpshufb    %[kShuffleUYVYUV], %%ymm3, %%ymm3                   \n" \
+  "vmovdqu    (%[uyvy_buf]),%%ymm1                                \n" \
+  "vpshufb    %%ymm6,%%ymm1,%%ymm4                                \n" \
+  "vpshufb    %%ymm7,%%ymm1,%%ymm3                                \n" \
   "lea        0x20(%[uyvy_buf]),%[uyvy_buf]                       \n"
 
 // TODO(fbarchard): Remove broadcastb
@@ -3631,17 +3378,17 @@
   "vpbroadcastq %%xmm8, %%zmm8                                    \n" \
   "vpsllw     $7,%%xmm13,%%xmm13                                  \n" \
   "vpbroadcastb %%xmm13,%%zmm13                                   \n" \
-  "movq     32(%[yuvconstants]),%%xmm9                            \n" \
+  "movq       32(%[yuvconstants]),%%xmm9                          \n" \
   "vpbroadcastq %%xmm9,%%zmm9                                     \n" \
-  "movq     64(%[yuvconstants]),%%xmm10                           \n" \
+  "movq       64(%[yuvconstants]),%%xmm10                         \n" \
   "vpbroadcastq %%xmm10,%%zmm10                                   \n" \
-  "movq     96(%[yuvconstants]),%%xmm11                           \n" \
+  "movq       96(%[yuvconstants]),%%xmm11                         \n" \
   "vpbroadcastq %%xmm11,%%zmm11                                   \n" \
-  "movq     128(%[yuvconstants]),%%xmm12                          \n" \
+  "movq       128(%[yuvconstants]),%%xmm12                        \n" \
   "vpbroadcastq %%xmm12,%%zmm12                                   \n" \
-  "vmovdqu8 (%[quadsplitperm]),%%zmm16                            \n" \
-  "vmovdqu8 (%[dquadsplitperm]),%%zmm17                           \n" \
-  "vmovdqu8 (%[unperm]),%%zmm18                                   \n"
+  "vmovups    (%[quadsplitperm]),%%zmm16                          \n" \
+  "vmovups    (%[dquadsplitperm]),%%zmm17                         \n" \
+  "vmovups    (%[unperm]),%%zmm18                                 \n"
 
 #define YUVTORGB16_AVX2(yuvconstants)                                 \
   "vpsubb      %%ymm13,%%ymm3,%%ymm3                              \n" \
@@ -3731,8 +3478,8 @@
   "vpermq     %%zmm2,%%zmm18,%%zmm2                               \n" \
   "vpunpcklwd %%zmm2,%%zmm0,%%zmm1                                \n" \
   "vpunpckhwd %%zmm2,%%zmm0,%%zmm0                                \n" \
-  "vmovdqu8   %%zmm1,(%[dst_argb])                                \n" \
-  "vmovdqu8   %%zmm0,0x40(%[dst_argb])                            \n" \
+  "vmovups    %%zmm1,(%[dst_argb])                                \n" \
+  "vmovups    %%zmm0,0x40(%[dst_argb])                            \n" \
   "lea        0x80(%[dst_argb]), %[dst_argb]                      \n"
 
 // Store 16 AR30 values.
@@ -3777,13 +3524,13 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV444_AVX2
     YUVTORGB_AVX2(yuvconstants)
     STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -3811,14 +3558,14 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422_AVX2
     YUVTORGB_AVX2(yuvconstants)
     STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -3852,14 +3599,14 @@
       "vpbroadcastq %%xmm5,%%zmm5                \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422_AVX512BW
     YUVTORGB_AVX512BW(yuvconstants)
     STOREARGB_AVX512BW
       "sub         $0x20,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),                         // %[y_buf]
     [u_buf]"+r"(u_buf),                         // %[u_buf]
     [v_buf]"+r"(v_buf),                         // %[v_buf]
@@ -3895,14 +3642,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -3930,14 +3677,14 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV210_AVX2
     YUVTORGB_AVX2(yuvconstants)
     STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -3965,14 +3712,14 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV212_AVX2
     YUVTORGB_AVX2(yuvconstants)
     STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -4005,14 +3752,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV210_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -4045,14 +3792,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV212_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -4080,13 +3827,13 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV410_AVX2
     YUVTORGB_AVX2(yuvconstants)
     STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
 
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
@@ -4110,29 +3857,28 @@
                                     uint8_t* dst_argb,
                                     const struct YuvConstants* yuvconstants,
                                     int width) {
-  asm volatile(
-      YUVTORGB_SETUP_AVX2(
-      yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-      LABELALIGN "1:                                        \n" READYUVA210_AVX2
-          YUVTORGB_AVX2(yuvconstants) STOREARGB_AVX2
-      "subl        $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
+               LABELALIGN "1:          \n" READYUVA210_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "subl        $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
 
-      : [y_buf] "+r"(y_buf),        // %[y_buf]
-        [u_buf] "+r"(u_buf),        // %[u_buf]
-        [v_buf] "+r"(v_buf),        // %[v_buf]
-        [a_buf] "+r"(a_buf),        // %[a_buf]
-        [dst_argb] "+r"(dst_argb),  // %[dst_argb]
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-        [width] "+m"(width)  // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-        [width] "+rm"(width)  // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-      : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-      : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2", "xmm3",
-        "xmm4", "xmm5");
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2",
+                 "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_I210TOARGBROW_AVX2
 
@@ -4146,29 +3892,28 @@
                                     uint8_t* dst_argb,
                                     const struct YuvConstants* yuvconstants,
                                     int width) {
-  asm volatile(
-      YUVTORGB_SETUP_AVX2(
-      yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-      LABELALIGN "1:                                        \n" READYUVA410_AVX2
-          YUVTORGB_AVX2(yuvconstants) STOREARGB_AVX2
-      "subl        $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
+               LABELALIGN "1:          \n" READYUVA410_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "subl        $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
 
-      : [y_buf] "+r"(y_buf),        // %[y_buf]
-        [u_buf] "+r"(u_buf),        // %[u_buf]
-        [v_buf] "+r"(v_buf),        // %[v_buf]
-        [a_buf] "+r"(a_buf),        // %[a_buf]
-        [dst_argb] "+r"(dst_argb),  // %[dst_argb]
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-        [width] "+m"(width)  // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-        [width] "+rm"(width)  // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-      : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
-      : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2", "xmm3",
-        "xmm4", "xmm5");
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2",
+                 "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_I410TOARGBROW_AVX2
 
@@ -4192,14 +3937,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV410_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [u_buf]"+r"(u_buf),    // %[u_buf]
     [v_buf]"+r"(v_buf),    // %[v_buf]
@@ -4222,34 +3967,27 @@
                                     uint8_t* dst_argb,
                                     const struct YuvConstants* yuvconstants,
                                     int width) {
-  // clang-format off
-  asm volatile (
-  YUVTORGB_SETUP_AVX2(yuvconstants)
-      "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-  LABELALIGN
-      "1:                                        \n"
-  READYUVA444_AVX2
-  YUVTORGB_AVX2(yuvconstants)
-  STOREARGB_AVX2
-      "subl        $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [u_buf]"+r"(u_buf),    // %[u_buf]
-    [v_buf]"+r"(v_buf),    // %[v_buf]
-    [a_buf]"+r"(a_buf),    // %[a_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA444_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "subl        $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-    [width]"+m"(width)     // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-    [width]"+rm"(width)    // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2",
+                 "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_I444ALPHATOARGBROW_AVX2
 
@@ -4263,34 +4001,27 @@
                                     uint8_t* dst_argb,
                                     const struct YuvConstants* yuvconstants,
                                     int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "sub         %[u_buf],%[v_buf]             \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "sub         %[u_buf],%[v_buf]             \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READYUVA422_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
-      "subl        $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [u_buf]"+r"(u_buf),    // %[u_buf]
-    [v_buf]"+r"(v_buf),    // %[v_buf]
-    [a_buf]"+r"(a_buf),    // %[a_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
+               LABELALIGN "1:          \n" READYUVA422_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "subl        $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),        // %[y_buf]
+                 [u_buf] "+r"(u_buf),        // %[u_buf]
+                 [v_buf] "+r"(v_buf),        // %[v_buf]
+                 [a_buf] "+r"(a_buf),        // %[a_buf]
+                 [dst_argb] "+r"(dst_argb),  // %[dst_argb]
 #if defined(__i386__)
-    [width]"+m"(width)     // %[width]
+                 [width] "+m"(width)  // %[width]
 #else
-    [width]"+rm"(width)    // %[width]
+                 [width] "+rm"(width)  // %[width]
 #endif
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS_AVX2
-    "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2",
+                 "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_I422ALPHATOARGBROW_AVX2
 
@@ -4309,7 +4040,7 @@
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READYUV422_AVX2
     YUVTORGB_AVX2(yuvconstants)
 
@@ -4346,28 +4077,21 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READNV12_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
-      "sub         $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [uv_buf]"+r"(uv_buf),    // %[uv_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-    : "memory", "cc", YUVTORGB_REGS_AVX2
-    "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READNV12_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "sub         $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[uv_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm0", "xmm1",
+                 "xmm2", "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_NV12TOARGBROW_AVX2
 
@@ -4379,29 +4103,22 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READNV21_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
-      "sub         $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [vu_buf]"+r"(vu_buf),    // %[vu_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleNV21]"m"(kShuffleNV21)
-    : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READNV21_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "sub         $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),               // %[y_buf]
+                 [vu_buf] "+r"(vu_buf),             // %[vu_buf]
+                 [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+                 [width] "+rm"(width)               // %[width]
+               : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+                 [kShuffleNV21] "m"(kShuffleNV21)
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm0", "xmm1",
+                 "xmm2", "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_NV21TOARGBROW_AVX2
 
@@ -4412,29 +4129,23 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(
+      "vbroadcastf128 %[kShuffleYUY2Y],%%ymm6    \n"
+      "vbroadcastf128 %[kShuffleYUY2UV],%%ymm7   \n" YUVTORGB_SETUP_AVX2(
+          yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READYUY2_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
+      LABELALIGN "1:          \n" READYUY2_AVX2 YUVTORGB_AVX2(yuvconstants)
+          STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [yuy2_buf]"+r"(yuy2_buf),    // %[yuy2_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleYUY2Y]"m"(kShuffleYUY2Y),
-    [kShuffleYUY2UV]"m"(kShuffleYUY2UV)
-    : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+      "vzeroupper  \n"
+      : [yuy2_buf] "+r"(yuy2_buf),         // %[yuy2_buf]
+        [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+        [width] "+rm"(width)               // %[width]
+      : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+        [kShuffleYUY2Y] "m"(kShuffleYUY2Y), [kShuffleYUY2UV] "m"(kShuffleYUY2UV)
+      : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm0", "xmm1", "xmm2",
+        "xmm3", "xmm4", "xmm5", "xmm6", "xmm7");
 }
 #endif  // HAS_YUY2TOARGBROW_AVX2
 
@@ -4445,29 +4156,23 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(
+      "vbroadcastf128 %[kShuffleUYVYY],%%ymm6    \n"
+      "vbroadcastf128 %[kShuffleUYVYUV],%%ymm7   \n" YUVTORGB_SETUP_AVX2(
+          yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READUYVY_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
+      LABELALIGN "1:          \n" READUYVY_AVX2 YUVTORGB_AVX2(yuvconstants)
+          STOREARGB_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [uyvy_buf]"+r"(uyvy_buf),    // %[uyvy_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants), // %[yuvconstants]
-    [kShuffleUYVYY]"m"(kShuffleUYVYY),
-    [kShuffleUYVYUV]"m"(kShuffleUYVYUV)
-    : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+      "vzeroupper  \n"
+      : [uyvy_buf] "+r"(uyvy_buf),         // %[uyvy_buf]
+        [dst_argb] "+r"(dst_argb),         // %[dst_argb]
+        [width] "+rm"(width)               // %[width]
+      : [yuvconstants] "r"(yuvconstants),  // %[yuvconstants]
+        [kShuffleUYVYY] "m"(kShuffleUYVYY), [kShuffleUYVYUV] "m"(kShuffleUYVYUV)
+      : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm1", "xmm2", "xmm3",
+        "xmm4", "xmm5", "xmm6", "xmm7");
 }
 #endif  // HAS_UYVYTOARGBROW_AVX2
 
@@ -4479,28 +4184,21 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READP210_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
-      "sub         $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [uv_buf]"+r"(uv_buf),    // %[uv_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READP210_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "sub         $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[uv_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm0", "xmm1",
+                 "xmm2", "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_P210TOARGBROW_AVX2
 
@@ -4512,28 +4210,21 @@
                                uint8_t* dst_argb,
                                const struct YuvConstants* yuvconstants,
                                int width) {
-  // clang-format off
-  asm volatile (
-    YUVTORGB_SETUP_AVX2(yuvconstants)
-      "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile(YUVTORGB_SETUP_AVX2(
+                   yuvconstants) "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"
 
-    LABELALIGN
-      "1:                                        \n"
-    READP410_AVX2
-    YUVTORGB_AVX2(yuvconstants)
-    STOREARGB_AVX2
-      "sub         $0x10,%[width]                \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : [y_buf]"+r"(y_buf),    // %[y_buf]
-    [uv_buf]"+r"(uv_buf),    // %[uv_buf]
-    [dst_argb]"+r"(dst_argb),  // %[dst_argb]
-    [width]"+rm"(width)    // %[width]
-  : [yuvconstants]"r"(yuvconstants)  // %[yuvconstants]
-  : "memory", "cc", YUVTORGB_REGS_AVX2
-      "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-  );
-  // clang-format on
+               LABELALIGN "1:          \n" READP410_AVX2 YUVTORGB_AVX2(
+                   yuvconstants) STOREARGB_AVX2
+               "sub         $0x10,%[width]                \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : [y_buf] "+r"(y_buf),              // %[y_buf]
+                 [uv_buf] "+r"(uv_buf),            // %[uv_buf]
+                 [dst_argb] "+r"(dst_argb),        // %[dst_argb]
+                 [width] "+rm"(width)              // %[width]
+               : [yuvconstants] "r"(yuvconstants)  // %[yuvconstants]
+               : "memory", "cc", YUVTORGB_REGS_AVX2 "xmm0", "xmm0", "xmm1",
+                 "xmm2", "xmm3", "xmm4", "xmm5");
 }
 #endif  // HAS_P410TOARGBROW_AVX2
 
@@ -4555,14 +4246,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READP210_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [uv_buf]"+r"(uv_buf),    // %[uv_buf]
     [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30]
@@ -4592,14 +4283,14 @@
       "vpsrlw      $6,%%ymm7,%%ymm7              \n"
 
     LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
     READP410_AVX2
     YUVTORGB16_AVX2(yuvconstants)
     STOREAR30_AVX2
       "sub         $0x10,%[width]                \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
   : [y_buf]"+r"(y_buf),    // %[y_buf]
     [uv_buf]"+r"(uv_buf),    // %[uv_buf]
     [dst_ar30]"+r"(dst_ar30),  // %[dst_ar30]
@@ -4623,7 +4314,7 @@
       "pslld       $0x18,%%xmm4                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164
       "movq      (%0),%%xmm0                     \n"
       "lea       0x8(%0),%0                      \n"
@@ -4668,7 +4359,7 @@
       "vpslld      $0x18,%%ymm4,%%ymm4           \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       // Step 1: Scale Y contribution to 16 G values. G = (y - 16) * 1.164
       "vmovdqu    (%0),%%xmm0                    \n"
       "lea        0x10(%0),%0                    \n"
@@ -4705,48 +4396,44 @@
 
 void MirrorRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("movdqa      %3,%%xmm5                     \n"
 
-      "movdqa      %3,%%xmm5                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      -0x10(%0,%2,1),%%xmm0         \n"
-      "pshufb      %%xmm5,%%xmm0                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      : "+r"(src),           // %0
-        "+r"(dst),           // %1
-        "+r"(temp_width)     // %2
-      : "m"(kShuffleMirror)  // %3
-      : "memory", "cc", "xmm0", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      -0x10(%0,%2,1),%%xmm0         \n"
+               "pshufb      %%xmm5,%%xmm0                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "lea         0x10(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               : "+r"(src),           // %0
+                 "+r"(dst),           // %1
+                 "+r"(temp_width)     // %2
+               : "m"(kShuffleMirror)  // %3
+               : "memory", "cc", "xmm0", "xmm5");
 }
 #endif  // HAS_MIRRORROW_SSSE3
 
 #ifdef HAS_MIRRORROW_AVX2
 void MirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("vbroadcastf128 %3,%%ymm5                  \n"
 
-      "vbroadcastf128 %3,%%ymm5                  \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     -0x20(%0,%2,1),%%ymm0         \n"
-      "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpermq      $0x4e,%%ymm0,%%ymm0           \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x20,%2                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src),           // %0
-        "+r"(dst),           // %1
-        "+r"(temp_width)     // %2
-      : "m"(kShuffleMirror)  // %3
-      : "memory", "cc", "xmm0", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "vmovdqu     -0x20(%0,%2,1),%%ymm0         \n"
+               "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
+               "vpermq      $0x4e,%%ymm0,%%ymm0           \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x20,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src),           // %0
+                 "+r"(dst),           // %1
+                 "+r"(temp_width)     // %2
+               : "m"(kShuffleMirror)  // %3
+               : "memory", "cc", "xmm0", "xmm5");
 }
 #endif  // HAS_MIRRORROW_AVX2
 
@@ -4757,48 +4444,44 @@
 
 void MirrorUVRow_SSSE3(const uint8_t* src_uv, uint8_t* dst_uv, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("movdqa      %3,%%xmm5                     \n"
 
-      "movdqa      %3,%%xmm5                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      -0x10(%0,%2,2),%%xmm0         \n"
-      "pshufb      %%xmm5,%%xmm0                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x8,%2                       \n"
-      "jg          1b                            \n"
-      : "+r"(src_uv),          // %0
-        "+r"(dst_uv),          // %1
-        "+r"(temp_width)       // %2
-      : "m"(kShuffleMirrorUV)  // %3
-      : "memory", "cc", "xmm0", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      -0x10(%0,%2,2),%%xmm0         \n"
+               "pshufb      %%xmm5,%%xmm0                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "lea         0x10(%1),%1                   \n"
+               "sub         $0x8,%2                       \n"
+               "jg          1b                            \n"
+               : "+r"(src_uv),          // %0
+                 "+r"(dst_uv),          // %1
+                 "+r"(temp_width)       // %2
+               : "m"(kShuffleMirrorUV)  // %3
+               : "memory", "cc", "xmm0", "xmm5");
 }
 #endif  // HAS_MIRRORUVROW_SSSE3
 
 #ifdef HAS_MIRRORUVROW_AVX2
 void MirrorUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_uv, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("vbroadcastf128 %3,%%ymm5                  \n"
 
-      "vbroadcastf128 %3,%%ymm5                  \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     -0x20(%0,%2,2),%%ymm0         \n"
-      "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpermq      $0x4e,%%ymm0,%%ymm0           \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_uv),          // %0
-        "+r"(dst_uv),          // %1
-        "+r"(temp_width)       // %2
-      : "m"(kShuffleMirrorUV)  // %3
-      : "memory", "cc", "xmm0", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "vmovdqu     -0x20(%0,%2,2),%%ymm0         \n"
+               "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
+               "vpermq      $0x4e,%%ymm0,%%ymm0           \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_uv),          // %0
+                 "+r"(dst_uv),          // %1
+                 "+r"(temp_width)       // %2
+               : "m"(kShuffleMirrorUV)  // %3
+               : "memory", "cc", "xmm0", "xmm5");
 }
 #endif  // HAS_MIRRORUVROW_AVX2
 
@@ -4817,7 +4500,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "lea         -0x10(%0),%0                  \n"
       "pshufb      %%xmm1,%%xmm0                 \n"
@@ -4856,7 +4539,7 @@
       "movdqa      %4,%%xmm5                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // first 5
       "movdqu      15(%0),%%xmm1                 \n"  // next 5
       "movdqu      30(%0),%%xmm2                 \n"  // next 5
@@ -4886,24 +4569,22 @@
 
 void ARGBMirrorRow_SSE2(const uint8_t* src, uint8_t* dst, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("lea         -0x10(%0,%2,4),%0             \n"
 
-      "lea         -0x10(%0,%2,4),%0             \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "pshufd      $0x1b,%%xmm0,%%xmm0           \n"
-      "lea         -0x10(%0),%0                  \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "lea         0x10(%1),%1                   \n"
-      "sub         $0x4,%2                       \n"
-      "jg          1b                            \n"
-      : "+r"(src),        // %0
-        "+r"(dst),        // %1
-        "+r"(temp_width)  // %2
-      :
-      : "memory", "cc", "xmm0");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "pshufd      $0x1b,%%xmm0,%%xmm0           \n"
+               "lea         -0x10(%0),%0                  \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "lea         0x10(%1),%1                   \n"
+               "sub         $0x4,%2                       \n"
+               "jg          1b                            \n"
+               : "+r"(src),        // %0
+                 "+r"(dst),        // %1
+                 "+r"(temp_width)  // %2
+               :
+               : "memory", "cc", "xmm0");
 }
 #endif  // HAS_ARGBMIRRORROW_SSE2
 
@@ -4912,23 +4593,21 @@
 static const ulvec32 kARGBShuffleMirror_AVX2 = {7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u};
 void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) {
   intptr_t temp_width = (intptr_t)(width);
-  asm volatile(
+  asm volatile("vmovdqu     %3,%%ymm5                     \n"
 
-      "vmovdqu     %3,%%ymm5                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vpermd      -0x20(%0,%2,4),%%ymm5,%%ymm0  \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x8,%2                       \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src),                    // %0
-        "+r"(dst),                    // %1
-        "+r"(temp_width)              // %2
-      : "m"(kARGBShuffleMirror_AVX2)  // %3
-      : "memory", "cc", "xmm0", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "vpermd      -0x20(%0,%2,4),%%ymm5,%%ymm0  \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x8,%2                       \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src),                    // %0
+                 "+r"(dst),                    // %1
+                 "+r"(temp_width)              // %2
+               : "m"(kARGBShuffleMirror_AVX2)  // %3
+               : "memory", "cc", "xmm0", "xmm5");
 }
 #endif  // HAS_ARGBMIRRORROW_AVX2
 
@@ -4943,7 +4622,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -4960,7 +4639,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_uv),  // %0
         "+r"(dst_u),   // %1
         "+r"(dst_v),   // %2
@@ -4981,7 +4660,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -5013,7 +4692,7 @@
                     uint8_t* dst,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "sub         $0x10,%2                      \n"
       "lea         (%0,%3),%0                    \n"
@@ -5034,7 +4713,7 @@
                        uint16_t* dst,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         (%0,%3,2),%0                  \n"
@@ -5057,14 +4736,14 @@
                       uint16_t* dst,
                       int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "lea         (%0,%3,2),%0                  \n"
       "vmovdqu     %%ymm0,(%1)                   \n"
       "lea         0x20(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),            // %0
         "+r"(dst),            // %1
         "+r"(width)           // %2
@@ -5082,7 +4761,7 @@
                        uint8_t* dst_yuy2,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // Load 16 Y
       "sub         $0x10,%3                      \n"
       "lea         (%0,%4),%0                    \n"
@@ -5122,7 +4801,7 @@
                             int width) {
   asm volatile(
       "movdqu      %4,%%xmm1                     \n"
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "lea         (%0, %5),%0                   \n"
       "pshufb      %%xmm1,%%xmm0                 \n"
@@ -5147,20 +4826,20 @@
                          const uint8_t* src_v,
                          uint8_t* dst_uv,
                          int width) {
-      asm volatile("sub         %0,%1                         \n"
+  asm volatile("sub         %0,%1                         \n"
 
                LABELALIGN
-      "1:                                        \n"
-      "vpmovzxbw   (%0),%%zmm0                   \n"
-      "vpmovzxbw   0x00(%0,%1,1),%%zmm1          \n"
-      "lea         0x20(%0),%0                   \n"
-      "vpsllw      $0x8,%%zmm1,%%zmm1            \n"
-      "vporq       %%zmm0,%%zmm1,%%zmm2          \n"
-      "vmovdqu64   %%zmm2,(%2)                   \n"
-      "lea         0x40(%2),%2                   \n"
-      "sub         $0x20,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
+               "1:          \n"
+               "vpmovzxbw   (%0),%%zmm0                   \n"
+               "vpmovzxbw   0x00(%0,%1,1),%%zmm1          \n"
+               "lea         0x20(%0),%0                   \n"
+               "vpsllw      $0x8,%%zmm1,%%zmm1            \n"
+               "vporq       %%zmm0,%%zmm1,%%zmm2          \n"
+               "vmovdqu64   %%zmm2,(%2)                   \n"
+               "lea         0x40(%2),%2                   \n"
+               "sub         $0x20,%3                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
                : "+r"(src_u),   // %0
                  "+r"(src_v),   // %1
                  "+r"(dst_uv),  // %2
@@ -5175,20 +4854,20 @@
                      const uint8_t* src_v,
                      uint8_t* dst_uv,
                      int width) {
-      asm volatile("sub         %0,%1                         \n"
+  asm volatile("sub         %0,%1                         \n"
 
                LABELALIGN
-      "1:                                        \n"
-      "vpmovzxbw   (%0),%%ymm0                   \n"
-      "vpmovzxbw   0x00(%0,%1,1),%%ymm1          \n"
-      "lea         0x10(%0),%0                   \n"
-      "vpsllw      $0x8,%%ymm1,%%ymm1            \n"
-      "vpor        %%ymm0,%%ymm1,%%ymm2          \n"
-      "vmovdqu     %%ymm2,(%2)                   \n"
-      "lea         0x20(%2),%2                   \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
+               "1:          \n"
+               "vpmovzxbw   (%0),%%ymm0                   \n"
+               "vpmovzxbw   0x00(%0,%1,1),%%ymm1          \n"
+               "lea         0x10(%0),%0                   \n"
+               "vpsllw      $0x8,%%ymm1,%%ymm1            \n"
+               "vpor        %%ymm0,%%ymm1,%%ymm2          \n"
+               "vmovdqu     %%ymm2,(%2)                   \n"
+               "lea         0x20(%2),%2                   \n"
+               "sub         $0x10,%3                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
                : "+r"(src_u),   // %0
                  "+r"(src_v),   // %1
                  "+r"(dst_uv),  // %2
@@ -5203,21 +4882,21 @@
                      const uint8_t* src_v,
                      uint8_t* dst_uv,
                      int width) {
-      asm volatile("sub         %0,%1                         \n"
+  asm volatile("sub         %0,%1                         \n"
 
                LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x00(%0,%1,1),%%xmm1          \n"
-      "lea         0x10(%0),%0                   \n"
-      "movdqa      %%xmm0,%%xmm2                 \n"
-      "punpcklbw   %%xmm1,%%xmm0                 \n"
-      "punpckhbw   %%xmm1,%%xmm2                 \n"
-      "movdqu      %%xmm0,(%2)                   \n"
-      "movdqu      %%xmm2,0x10(%2)               \n"
-      "lea         0x20(%2),%2                   \n"
-      "sub         $0x10,%3                      \n"
-      "jg          1b                            \n"
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x00(%0,%1,1),%%xmm1          \n"
+               "lea         0x10(%0),%0                   \n"
+               "movdqa      %%xmm0,%%xmm2                 \n"
+               "punpcklbw   %%xmm1,%%xmm0                 \n"
+               "punpckhbw   %%xmm1,%%xmm2                 \n"
+               "movdqu      %%xmm0,(%2)                   \n"
+               "movdqu      %%xmm2,0x10(%2)               \n"
+               "lea         0x20(%2),%2                   \n"
+               "sub         $0x10,%3                      \n"
+               "jg          1b                            \n"
                : "+r"(src_u),   // %0
                  "+r"(src_v),   // %1
                  "+r"(dst_uv),  // %2
@@ -5233,17 +4912,15 @@
                         uint16_t* dst_uv,
                         int depth,
                         int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %4,%%xmm3                     \n"
       "vmovd       %5,%%xmm4                     \n"
 
-
       "sub         %0,%1                         \n"
       // 8 pixels per loop.
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vpmovzxwd   (%0),%%ymm0                   \n"
       "vpmovzxwd   0x00(%0,%1,1),%%ymm1          \n"
       "lea         0x10(%0),%0                   \n"
@@ -5254,15 +4931,14 @@
       "lea         0x20(%2),%2                   \n"
       "sub         $0x8,%3                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_u),      // %0
-    "+r"(src_v),      // %1
-    "+r"(dst_uv),     // %2
-    "+r"(width)       // %3
-  : "r"(16 - depth),  // %4
-    "r"(32 - depth)   // %5
-  : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_u),      // %0
+        "+r"(src_v),      // %1
+        "+r"(dst_uv),     // %2
+        "+r"(width)       // %3
+      : "r"(16 - depth),  // %4
+        "r"(32 - depth)   // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
 }
 #endif  // HAS_MERGEUVROW_AVX2
 
@@ -5275,15 +4951,14 @@
                         int depth,
                         int width) {
   depth = 16 - depth;
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %4,%%xmm3                     \n"
       "vbroadcastf128 %5,%%ymm4                  \n"
       "sub         %1,%2                         \n"
 
-    // 16 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 16 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "add         $0x40,%0                      \n"
@@ -5301,15 +4976,14 @@
       "add         $0x20,%1                      \n"
       "sub         $0x10,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_uv),   // %0
-    "+r"(dst_u),    // %1
-    "+r"(dst_v),    // %2
-    "+r"(width)     // %3
-  : "r"(depth),     // %4
-    "m"(kSplitUVShuffle16) // %5
-  : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_uv),           // %0
+        "+r"(dst_u),            // %1
+        "+r"(dst_v),            // %2
+        "+r"(width)             // %3
+      : "r"(depth),             // %4
+        "m"(kSplitUVShuffle16)  // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
 }
 #endif  // HAS_SPLITUVROW_16_AVX2
 
@@ -5323,16 +4997,14 @@
                          uint16_t* dst_y,
                          int scale,
                          int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %3,%%xmm3                     \n"
-      "vpunpcklwd  %%xmm3,%%xmm3,%%xmm3          \n"
-      "vbroadcastss %%xmm3,%%ymm3                \n"
+      "vpbroadcastw %%xmm3,%%ymm3                \n"
       "sub         %0,%1                         \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpmullw     %%ymm3,%%ymm0,%%ymm0          \n"
@@ -5342,13 +5014,12 @@
       "add         $0x40,%0                      \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width)    // %2
-  : "r"(scale)     // %3
-  : "memory", "cc", "xmm0", "xmm1", "xmm3");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale)    // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm3");
 }
 #endif  // HAS_MULTIPLYROW_16_AVX2
 
@@ -5362,16 +5033,14 @@
                        uint16_t* dst_y,
                        int scale,
                        int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %3,%%xmm3                     \n"
-      "vpunpcklwd  %%xmm3,%%xmm3,%%xmm3          \n"
-      "vbroadcastss %%xmm3,%%ymm3                \n"
+      "vpbroadcastw %%xmm3,%%ymm3                \n"
       "sub         %0,%1                         \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpmulhuw    %%ymm3,%%ymm0,%%ymm0          \n"
@@ -5381,14 +5050,13 @@
       "add         $0x40,%0                      \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width),    // %2
-    "+r"(scale)     // %3
-  :
-  : "memory", "cc", "xmm0", "xmm1", "xmm3");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width),  // %2
+        "+r"(scale)   // %3
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm3");
 }
 #endif  // HAS_MULTIPLYROW_16_AVX2
 
@@ -5401,15 +5069,14 @@
                            uint8_t* dst_y,
                            int scale,
                            int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "movd        %3,%%xmm2                     \n"
       "punpcklwd   %%xmm2,%%xmm2                 \n"
       "pshufd      $0x0,%%xmm2,%%xmm2            \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "add         $0x20,%0                      \n"
@@ -5420,12 +5087,11 @@
       "add         $0x10,%1                      \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width)    // %2
-  : "r"(scale)     // %3
-  : "memory", "cc", "xmm0", "xmm1", "xmm2");
-  // clang-format on
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale)    // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 
 #ifdef HAS_CONVERT16TO8ROW_AVX2
@@ -5433,15 +5099,13 @@
                           uint8_t* dst_y,
                           int scale,
                           int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %3,%%xmm2                     \n"
-      "vpunpcklwd  %%xmm2,%%xmm2,%%xmm2          \n"
-      "vbroadcastss %%xmm2,%%ymm2                \n"
+      "vpbroadcastw %%xmm2,%%ymm2                \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "add         $0x40,%0                      \n"
@@ -5453,13 +5117,43 @@
       "add         $0x20,%1                      \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width)    // %2
-  : "r"(scale)     // %3
-  : "memory", "cc", "xmm0", "xmm1", "xmm2");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale)    // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+}
+#endif  // HAS_CONVERT16TO8ROW_AVX2
+
+#ifdef HAS_CONVERT16TO8ROW_AVX512BW
+void Convert16To8Row_AVX512BW(const uint16_t* src_y,
+                              uint8_t* dst_y,
+                              int scale,
+                              int width) {
+  asm volatile("vpbroadcastw %3,%%zmm2                    \n"
+
+               // 64 pixels per loop.
+               LABELALIGN
+               "1:          \n"
+               "vmovups     (%0),%%zmm0                   \n"
+               "vmovups     0x40(%0),%%zmm1               \n"
+               "add         $0x80,%0                      \n"
+               "vpmulhuw    %%zmm2,%%zmm0,%%zmm0          \n"
+               "vpmulhuw    %%zmm2,%%zmm1,%%zmm1          \n"
+               "vpmovuswb   %%zmm0,%%ymm0                 \n"
+               "vpmovuswb   %%zmm1,%%ymm1                 \n"
+               "vmovups     %%ymm0,(%1)                   \n"
+               "vmovups     %%ymm1,0x20(%1)               \n"
+               "add         $0x40,%1                      \n"
+               "sub         $0x40,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_y),  // %0
+                 "+r"(dst_y),  // %1
+                 "+r"(width)   // %2
+               : "r"(scale)    // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_CONVERT16TO8ROW_AVX2
 
@@ -5471,15 +5165,14 @@
                           uint16_t* dst_y,
                           int scale,
                           int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "movd        %3,%%xmm2                     \n"
       "punpcklwd   %%xmm2,%%xmm2                 \n"
       "pshufd      $0x0,%%xmm2,%%xmm2            \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
       "punpcklbw   %%xmm0,%%xmm0                 \n"
@@ -5492,12 +5185,11 @@
       "add         $0x20,%1                      \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width)    // %2
-  : "r"(scale)     // %3
-  : "memory", "cc", "xmm0", "xmm1", "xmm2");
-  // clang-format on
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale)    // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 
 #ifdef HAS_CONVERT8TO16ROW_AVX2
@@ -5505,15 +5197,13 @@
                           uint16_t* dst_y,
                           int scale,
                           int width) {
-  // clang-format off
-  asm volatile (
+  asm volatile(
       "vmovd       %3,%%xmm2                     \n"
-      "vpunpcklwd  %%xmm2,%%xmm2,%%xmm2          \n"
-      "vbroadcastss %%xmm2,%%ymm2                \n"
+      "vpbroadcastw %%xmm2,%%ymm2                \n"
 
-    // 32 pixels per loop.
-    LABELALIGN
-      "1:                                        \n"
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vpermq      $0xd8,%%ymm0,%%ymm0           \n"
       "add         $0x20,%0                      \n"
@@ -5526,13 +5216,12 @@
       "add         $0x40,%1                      \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-  : "+r"(src_y),   // %0
-    "+r"(dst_y),   // %1
-    "+r"(width)    // %2
-  : "r"(scale)     // %3
-  : "memory", "cc", "xmm0", "xmm1", "xmm2");
-  // clang-format on
+      "vzeroupper  \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale)    // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_CONVERT8TO16ROW_AVX2
 
@@ -5564,9 +5253,7 @@
                        uint8_t* dst_b,
                        int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm2               \n"
@@ -5612,6 +5299,123 @@
 }
 #endif  // HAS_SPLITRGBROW_SSSE3
 
+#ifdef HAS_SPLITRGBROW_SSE41
+// Shuffle table for converting RGB to Planar, SSE4.1. Note: these are used for
+// the AVX2 implementation as well.
+static const uvec8 kSplitRGBShuffleSSE41[5] = {
+    {0u, 3u, 6u, 9u, 12u, 15u, 2u, 5u, 8u, 11u, 14u, 1u, 4u, 7u, 10u, 13u},
+    {1u, 4u, 7u, 10u, 13u, 0u, 3u, 6u, 9u, 12u, 15u, 2u, 5u, 8u, 11u, 14u},
+    {2u, 5u, 8u, 11u, 14u, 1u, 4u, 7u, 10u, 13u, 0u, 3u, 6u, 9u, 12u, 15u},
+    {0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u},
+    {0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u, 0u, 128u, 0u},
+};
+
+void SplitRGBRow_SSE41(const uint8_t* src_rgb,
+                       uint8_t* dst_r,
+                       uint8_t* dst_g,
+                       uint8_t* dst_b,
+                       int width) {
+  asm volatile(
+      "movdqa      48(%5), %%xmm0                \n"
+      "1:          \n"
+      "movdqu      (%0),%%xmm1                   \n"
+      "movdqu      0x10(%0),%%xmm2               \n"
+      "movdqu      0x20(%0),%%xmm3               \n"
+      "lea         0x30(%0),%0                   \n"
+      "movdqa      %%xmm1, %%xmm4                \n"
+      "pblendvb    %%xmm3, %%xmm1                \n"
+      "pblendvb    %%xmm2, %%xmm3                \n"
+      "pblendvb    %%xmm4, %%xmm2                \n"
+      "palignr     $0xF, %%xmm0, %%xmm0          \n"
+      "pblendvb    %%xmm2, %%xmm1                \n"
+      "pblendvb    %%xmm3, %%xmm2                \n"
+      "pblendvb    %%xmm4, %%xmm3                \n"
+      "palignr     $0x1, %%xmm0, %%xmm0          \n"
+      "pshufb      0(%5), %%xmm1                 \n"
+      "pshufb      16(%5), %%xmm2                \n"
+      "pshufb      32(%5), %%xmm3                \n"
+      "movdqu      %%xmm1,(%1)                   \n"
+      "lea         0x10(%1),%1                   \n"
+      "movdqu      %%xmm2,(%2)                   \n"
+      "lea         0x10(%2),%2                   \n"
+      "movdqu      %%xmm3,(%3)                   \n"
+      "lea         0x10(%3),%3                   \n"
+      "sub         $0x10,%4                      \n"
+      "jg          1b                            \n"
+      : "+r"(src_rgb),                  // %0
+        "+r"(dst_r),                    // %1
+        "+r"(dst_g),                    // %2
+        "+r"(dst_b),                    // %3
+        "+r"(width)                     // %4
+      : "r"(&kSplitRGBShuffleSSE41[0])  // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
+}
+#endif  // HAS_SPLITRGBROW_SSE41
+
+#ifdef HAS_SPLITRGBROW_AVX2
+void SplitRGBRow_AVX2(const uint8_t* src_rgb,
+                      uint8_t* dst_r,
+                      uint8_t* dst_g,
+                      uint8_t* dst_b,
+                      int width) {
+  asm volatile(
+      "vbroadcasti128 48(%5), %%ymm0             \n"
+      "vbroadcasti128 64(%5), %%ymm7             \n"
+#if defined(__x86_64__)
+      "vbroadcasti128 0(%5), %%ymm8              \n"
+      "vbroadcasti128 16(%5), %%ymm9             \n"
+      "vbroadcasti128 32(%5), %%ymm10            \n"
+#endif
+      "1:          \n"
+      "vmovdqu     (%0),%%ymm4                   \n"
+      "vmovdqu     0x20(%0),%%ymm5               \n"
+      "vmovdqu     0x40(%0),%%ymm6               \n"
+      "lea         0x60(%0),%0                   \n"
+      "vpblendd    $240, %%ymm5, %%ymm4, %%ymm1  \n"
+      "vperm2i128  $33, %%ymm6, %%ymm4, %%ymm2   \n"
+      "vpblendd    $240, %%ymm6, %%ymm5, %%ymm3  \n"
+      "vpblendvb   %%ymm0, %%ymm3, %%ymm1, %%ymm4 \n"
+      "vpblendvb   %%ymm0, %%ymm1, %%ymm2, %%ymm5 \n"
+      "vpblendvb   %%ymm0, %%ymm2, %%ymm3, %%ymm6 \n"
+      "vpblendvb   %%ymm7, %%ymm5, %%ymm4, %%ymm1 \n"
+      "vpblendvb   %%ymm7, %%ymm6, %%ymm5, %%ymm2 \n"
+      "vpblendvb   %%ymm7, %%ymm4, %%ymm6, %%ymm3 \n"
+#if defined(__x86_64__)
+      "vpshufb     %%ymm8, %%ymm1, %%ymm1        \n"
+      "vpshufb     %%ymm9, %%ymm2, %%ymm2        \n"
+      "vpshufb     %%ymm10, %%ymm3, %%ymm3       \n"
+#else
+      "vbroadcasti128 0(%5), %%ymm4              \n"
+      "vbroadcasti128 16(%5), %%ymm5             \n"
+      "vbroadcasti128 32(%5), %%ymm6             \n"
+      "vpshufb     %%ymm4, %%ymm1, %%ymm1        \n"
+      "vpshufb     %%ymm5, %%ymm2, %%ymm2        \n"
+      "vpshufb     %%ymm6, %%ymm3, %%ymm3        \n"
+#endif
+      "vmovdqu     %%ymm1,(%1)                   \n"
+      "lea         0x20(%1),%1                   \n"
+      "vmovdqu     %%ymm2,(%2)                   \n"
+      "lea         0x20(%2),%2                   \n"
+      "vmovdqu     %%ymm3,(%3)                   \n"
+      "lea         0x20(%3),%3                   \n"
+      "sub         $0x20,%4                      \n"
+      "jg          1b                            \n"
+      : "+r"(src_rgb),                  // %0
+        "+r"(dst_r),                    // %1
+        "+r"(dst_g),                    // %2
+        "+r"(dst_b),                    // %3
+        "+r"(width)                     // %4
+      : "r"(&kSplitRGBShuffleSSE41[0])  // %5
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7"
+#if defined(__x86_64__)
+        ,
+        "xmm8", "xmm9", "xmm10"
+#endif
+  );
+}
+#endif  // HAS_SPLITRGBROW_AVX2
+
 #ifdef HAS_MERGERGBROW_SSSE3
 // Shuffle table for converting Planar to RGB.
 static const uvec8 kMergeRGBShuffle[9] = {
@@ -5640,9 +5444,7 @@
                        uint8_t* dst_rgb,
                        int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      (%1),%%xmm1                   \n"
       "movdqu      (%2),%%xmm2                   \n"
@@ -5697,13 +5499,12 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "sub         %0,%3                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movq        (%0,%2),%%xmm0                \n"  // B
       "movq        (%0),%%xmm1                   \n"  // R
@@ -5739,9 +5540,7 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movq        (%2),%%xmm0                   \n"  // B
       "movq        (%0),%%xmm1                   \n"  // R
@@ -5779,13 +5578,12 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "sub         %0,%3                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0,%2),%%xmm0                \n"  // B
       "vmovdqu     (%0,%1),%%xmm1                \n"  // R
@@ -5806,7 +5604,7 @@
       "lea         64(%4),%4                     \n"
       "sub         $0x10,%5                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
@@ -5825,12 +5623,10 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%2),%%xmm0                   \n"  // B
-      "vpcmpeqd    %%ymm1,%%ymm1,%%ymm1          \n"  // A(255)
+      "vpcmpeqb    %%ymm1,%%ymm1,%%ymm1          \n"  // A(255)
       "vinserti128 $0,(%1),%%ymm1,%%ymm1         \n"  // R
       "vinserti128 $1,(%0),%%ymm0,%%ymm0         \n"  // G
       "vpunpckhbw  %%ymm1,%%ymm0,%%ymm2          \n"
@@ -5850,14 +5646,14 @@
       "lea         64(%3),%3                     \n"
       "sub         $0x10,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
         "+r"(dst_argb),  // %3
         "+rm"(width)     // %4
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+        ::"memory",
+        "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_MERGEARGBROW_AVX2
 
@@ -5869,13 +5665,12 @@
                        uint8_t* dst_a,
                        int width) {
   asm volatile(
-
       "sub         %1,%2                         \n"
       "sub         %1,%3                         \n"
       "sub         %1,%4                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movdqu      (%0),%%xmm0                   \n"  // 00-0F
       "movdqu      16(%0),%%xmm1                 \n"  // 10-1F
@@ -5921,9 +5716,7 @@
                        uint8_t* dst_b,
                        int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movdqu      (%0),%%xmm0                   \n"  // 00-0F
       "movdqu      16(%0),%%xmm1                 \n"  // 10-1F
@@ -5972,14 +5765,13 @@
                         uint8_t* dst_a,
                         int width) {
   asm volatile(
-
       "movdqa      %6,%%xmm3                     \n"
       "sub         %1,%2                         \n"
       "sub         %1,%3                         \n"
       "sub         %1,%4                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movdqu      (%0),%%xmm0                   \n"  // 00-0F
       "movdqu      16(%0),%%xmm1                 \n"  // 10-1F
@@ -6005,7 +5797,7 @@
 #if defined(__i386__)
         "+m"(width)  // %5
 #else
-        "+rm"(width)          // %5
+        "+rm"(width)  // %5
 #endif
       : "m"(kShuffleMaskARGBSplit)  // %6
       : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
@@ -6019,11 +5811,10 @@
                         uint8_t* dst_b,
                         int width) {
   asm volatile(
-
       "movdqa      %5,%%xmm3                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "movdqu      (%0),%%xmm0                   \n"  // 00-0F
       "movdqu      16(%0),%%xmm1                 \n"  // 10-1F
@@ -6061,7 +5852,6 @@
                        uint8_t* dst_a,
                        int width) {
   asm volatile(
-
       "sub         %1,%2                         \n"
       "sub         %1,%3                         \n"
       "sub         %1,%4                         \n"
@@ -6069,7 +5859,7 @@
       "vbroadcastf128 %6,%%ymm4                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0),%%xmm0                   \n"  // 00-0F
       "vmovdqu     16(%0),%%xmm1                 \n"  // 10-1F
@@ -6089,7 +5879,7 @@
       "lea         16(%1),%1                     \n"
       "subl        $0x10,%5                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),  // %0
         "+r"(dst_r),     // %1
         "+r"(dst_g),     // %2
@@ -6098,7 +5888,7 @@
 #if defined(__i386__)
         "+m"(width)  // %5
 #else
-        "+rm"(width)          // %5
+        "+rm"(width)  // %5
 #endif
       : "m"(kShuffleMaskARGBSplit),   // %6
         "m"(kShuffleMaskARGBPermute)  // %7
@@ -6113,12 +5903,11 @@
                        uint8_t* dst_b,
                        int width) {
   asm volatile(
-
       "vmovdqa     %6,%%ymm3                     \n"
       "vbroadcastf128 %5,%%ymm4                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0),%%xmm0                   \n"  // 00-0F
       "vmovdqu     16(%0),%%xmm1                 \n"  // 10-1F
@@ -6140,7 +5929,7 @@
       "lea         16(%3),%3                     \n"
       "sub         $0x10,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),               // %0
         "+r"(dst_r),                  // %1
         "+r"(dst_g),                  // %2
@@ -6161,7 +5950,6 @@
                        int width) {
   int shift = depth - 10;
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "vpcmpeqb    %%ymm5,%%ymm5,%%ymm5          \n"  // AR30 constants
@@ -6172,7 +5960,7 @@
       "vmovd       %5,%%xmm4                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     (%0,%1),%%ymm1                \n"
       "vmovdqu     (%0,%2),%%ymm2                \n"
@@ -6200,7 +5988,7 @@
       "lea         0x40(%3),%3                   \n"
       "sub         $0x10,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
@@ -6209,7 +5997,7 @@
 #if defined(__i386__)
       : "m"(shift)  // %5
 #else
-      : "rm"(shift)           // %5
+      : "rm"(shift)   // %5
 #endif
       : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
 }
@@ -6228,7 +6016,6 @@
   int mask = (1 << depth) - 1;
   mask = (mask << 16) + mask;
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "sub         %0,%3                         \n"
@@ -6237,7 +6024,7 @@
       "vbroadcastss %7,%%ymm7                    \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // R
       "vmovdqu     (%0,%1),%%ymm1                \n"  // G
       "vmovdqu     (%0,%2),%%ymm2                \n"  // B
@@ -6270,7 +6057,7 @@
       "lea         0x80(%4),%4                   \n"
       "subl        $0x10,%5                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
@@ -6279,7 +6066,7 @@
 #if defined(__i386__)
         "+m"(width)  // %5
 #else
-        "+rm"(width)          // %5
+        "+rm"(width)  // %5
 #endif
       : "m"(shift),            // %6
         "m"(mask),             // %7
@@ -6300,7 +6087,6 @@
   int mask = (1 << depth) - 1;
   mask = (mask << 16) + mask;
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "vmovdqa     %7,%%ymm5                     \n"
@@ -6308,7 +6094,7 @@
       "vbroadcastss %6,%%ymm7                    \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // R
       "vmovdqu     (%0,%1),%%ymm1                \n"  // G
       "vmovdqu     (%0,%2),%%ymm2                \n"  // B
@@ -6338,7 +6124,7 @@
       "lea         0x80(%3),%3                   \n"
       "subl        $0x10,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),           // %0
         "+r"(src_g),           // %1
         "+r"(src_b),           // %2
@@ -6364,7 +6150,6 @@
                             int width) {
   int shift = depth - 8;
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "sub         %0,%3                         \n"
@@ -6372,7 +6157,7 @@
       "vmovd       %6,%%xmm6                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // R
       "vmovdqu     (%0,%1),%%ymm1                \n"  // G
       "vmovdqu     (%0,%2),%%ymm2                \n"  // B
@@ -6395,7 +6180,7 @@
       "lea         0x40(%4),%4                   \n"
       "subl        $0x10,%5                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
@@ -6404,7 +6189,7 @@
 #if defined(__i386__)
         "+m"(width)  // %5
 #else
-        "+rm"(width)          // %5
+        "+rm"(width)  // %5
 #endif
       : "m"(shift),                 // %6
         "m"(MergeARGB16To8Shuffle)  // %7
@@ -6421,7 +6206,6 @@
                             int width) {
   int shift = depth - 8;
   asm volatile(
-
       "sub         %0,%1                         \n"
       "sub         %0,%2                         \n"
       "vbroadcastf128 %6,%%ymm5                  \n"
@@ -6430,7 +6214,7 @@
       "vpsrlw      $8,%%ymm3,%%ymm3              \n"  // A (0xff)
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // R
       "vmovdqu     (%0,%1),%%ymm1                \n"  // G
       "vmovdqu     (%0,%2),%%ymm2                \n"  // B
@@ -6451,7 +6235,7 @@
       "lea         0x40(%3),%3                   \n"
       "subl        $0x10,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_r),                // %0
         "+r"(src_g),                // %1
         "+r"(src_b),                // %2
@@ -6472,7 +6256,7 @@
       "jne         2f                            \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqa      (%0),%%xmm0                   \n"
       "movdqa      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6484,7 +6268,7 @@
       "jmp         9f                            \n"
 
       LABELALIGN
-      "2:                                        \n"
+      "2:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6494,7 +6278,7 @@
       "sub         $0x20,%2                      \n"
       "jg          2b                            \n"
 
-      LABELALIGN "9:                                        \n"
+      LABELALIGN "9:          \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
@@ -6506,9 +6290,7 @@
 #ifdef HAS_COPYROW_AVX
 void CopyRow_AVX(const uint8_t* src, uint8_t* dst, int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -6517,7 +6299,7 @@
       "lea         0x40(%1),%1                   \n"
       "sub         $0x40,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
@@ -6526,18 +6308,37 @@
 }
 #endif  // HAS_COPYROW_AVX
 
+#ifdef HAS_COPYROW_AVX512BW
+void CopyRow_AVX512BW(const uint8_t* src, uint8_t* dst, int width) {
+  asm volatile(
+      "1:          \n"
+      "vmovups     (%0),%%zmm0                   \n"
+      "vmovups     0x40(%0),%%zmm1               \n"
+      "lea         0x80(%0),%0                   \n"
+      "vmovups     %%zmm0,(%1)                   \n"
+      "vmovups     %%zmm1,0x40(%1)               \n"
+      "lea         0x80(%1),%1                   \n"
+      "sub         $0x80,%2                      \n"
+      "jg          1b                            \n"
+      "vzeroupper  \n"
+      : "+r"(src),   // %0
+        "+r"(dst),   // %1
+        "+r"(width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
+}
+#endif  // HAS_COPYROW_AVX512
+
 #ifdef HAS_COPYROW_ERMS
 // Multiple of 1.
 void CopyRow_ERMS(const uint8_t* src, uint8_t* dst, int width) {
   size_t width_tmp = (size_t)(width);
-  asm volatile(
-
-      "rep         movsb                         \n"
-      : "+S"(src),       // %0
-        "+D"(dst),       // %1
-        "+c"(width_tmp)  // %2
-      :
-      : "memory", "cc");
+  asm volatile("rep         movsb                         \n"
+               : "+S"(src),       // %0
+                 "+D"(dst),       // %1
+                 "+c"(width_tmp)  // %2
+               :
+               : "memory", "cc");
 }
 #endif  // HAS_COPYROW_ERMS
 
@@ -6551,7 +6352,7 @@
       "psrld       $0x8,%%xmm1                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm2                   \n"
       "movdqu      0x10(%0),%%xmm3               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6584,7 +6385,7 @@
       "vpsrld      $0x8,%%ymm0,%%ymm0            \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm1                   \n"
       "vmovdqu     0x20(%0),%%ymm2               \n"
       "lea         0x40(%0),%0                   \n"
@@ -6595,7 +6396,7 @@
       "lea         0x40(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
@@ -6610,9 +6411,7 @@
                               uint8_t* dst_a,
                               int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0), %%xmm0                  \n"
       "movdqu      0x10(%0), %%xmm1              \n"
       "lea         0x20(%0), %0                  \n"
@@ -6645,7 +6444,7 @@
       "vbroadcastf128 %4,%%ymm5                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0), %%ymm0                  \n"
       "vmovdqu     0x20(%0), %%ymm1              \n"
       "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"  // vpsrld $0x18, %%ymm0
@@ -6663,7 +6462,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20, %2                     \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),               // %0
         "+r"(dst_a),                  // %1
         "+rm"(width)                  // %2
@@ -6683,7 +6482,7 @@
       "psrld       $0x8,%%xmm1                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm2                   \n"
       "lea         0x8(%0),%0                    \n"
       "punpcklbw   %%xmm2,%%xmm2                 \n"
@@ -6718,7 +6517,7 @@
       "vpsrld      $0x8,%%ymm0,%%ymm0            \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vpmovzxbd   (%0),%%ymm1                   \n"
       "vpmovzxbd   0x8(%0),%%ymm2                \n"
       "lea         0x10(%0),%0                   \n"
@@ -6731,7 +6530,7 @@
       "lea         0x40(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
@@ -6744,35 +6543,29 @@
 void SetRow_X86(uint8_t* dst, uint8_t v8, int width) {
   size_t width_tmp = (size_t)(width >> 2);
   const uint32_t v32 = v8 * 0x01010101u;  // Duplicate byte to all bytes.
-  asm volatile(
-
-      "rep         stosl                         \n"
-      : "+D"(dst),       // %0
-        "+c"(width_tmp)  // %1
-      : "a"(v32)         // %2
-      : "memory", "cc");
+  asm volatile("rep         stosl                         \n"
+               : "+D"(dst),       // %0
+                 "+c"(width_tmp)  // %1
+               : "a"(v32)         // %2
+               : "memory", "cc");
 }
 
 void SetRow_ERMS(uint8_t* dst, uint8_t v8, int width) {
   size_t width_tmp = (size_t)(width);
-  asm volatile(
-
-      "rep         stosb                         \n"
-      : "+D"(dst),       // %0
-        "+c"(width_tmp)  // %1
-      : "a"(v8)          // %2
-      : "memory", "cc");
+  asm volatile("rep         stosb                         \n"
+               : "+D"(dst),       // %0
+                 "+c"(width_tmp)  // %1
+               : "a"(v8)          // %2
+               : "memory", "cc");
 }
 
 void ARGBSetRow_X86(uint8_t* dst_argb, uint32_t v32, int width) {
   size_t width_tmp = (size_t)(width);
-  asm volatile(
-
-      "rep         stosl                         \n"
-      : "+D"(dst_argb),  // %0
-        "+c"(width_tmp)  // %1
-      : "a"(v32)         // %2
-      : "memory", "cc");
+  asm volatile("rep         stosl                         \n"
+               : "+D"(dst_argb),  // %0
+                 "+c"(width_tmp)  // %1
+               : "a"(v32)         // %2
+               : "memory", "cc");
 }
 #endif  // HAS_SETROW_X86
 
@@ -6783,7 +6576,7 @@
       "psrlw       $0x8,%%xmm5                   \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6805,8 +6598,8 @@
                         int stride_yuy2,
                         uint8_t* dst_uv,
                         int width) {
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%3,1),%%xmm2          \n"
@@ -6821,11 +6614,11 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-               : "+r"(src_yuy2),               // %0
-                 "+r"(dst_uv),                 // %1
-                 "+r"(width)                   // %2
-               : "r"((intptr_t)(stride_yuy2))  // %3
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
+      : "+r"(src_yuy2),               // %0
+        "+r"(dst_uv),                 // %1
+        "+r"(width)                   // %2
+      : "r"((intptr_t)(stride_yuy2))  // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
 }
 
 void YUY2ToUVRow_SSE2(const uint8_t* src_yuy2,
@@ -6839,7 +6632,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%4,1),%%xmm2          \n"
@@ -6878,7 +6671,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6905,9 +6698,7 @@
 
 void UYVYToYRow_SSE2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -6936,7 +6727,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%4,1),%%xmm2          \n"
@@ -6975,7 +6766,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -7008,7 +6799,7 @@
       "vpsrlw      $0x8,%%ymm5,%%ymm5            \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -7020,7 +6811,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_yuy2),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
@@ -7033,9 +6824,7 @@
                         uint8_t* dst_uv,
                         int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpavgb      0x00(%0,%3,1),%%ymm0,%%ymm0   \n"
@@ -7049,7 +6838,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_yuy2),               // %0
         "+r"(dst_uv),                 // %1
         "+r"(width)                   // %2
@@ -7068,7 +6857,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
@@ -7089,7 +6878,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x20,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_yuy2),               // %0
         "+r"(dst_u),                  // %1
         "+r"(dst_v),                  // %2
@@ -7108,7 +6897,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -7127,7 +6916,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x20,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_yuy2),  // %0
         "+r"(dst_u),     // %1
         "+r"(dst_v),     // %2
@@ -7138,9 +6927,7 @@
 
 void UYVYToYRow_AVX2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) {
   asm volatile(
-
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -7152,7 +6939,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_uyvy),  // %0
         "+r"(dst_y),     // %1
         "+r"(width)      // %2
@@ -7170,7 +6957,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vpavgb      0x00(%0,%4,1),%%ymm0,%%ymm0   \n"
@@ -7191,7 +6978,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x20,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_uyvy),               // %0
         "+r"(dst_u),                  // %1
         "+r"(dst_v),                  // %2
@@ -7210,7 +6997,7 @@
       "sub         %1,%2                         \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -7229,7 +7016,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x20,%3                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_uyvy),  // %0
         "+r"(dst_u),     // %1
         "+r"(dst_v),     // %2
@@ -7263,7 +7050,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "40:                                       \n"
+      "40:         \n"
       "movdqu      (%0),%%xmm3                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqa      %%xmm3,%%xmm0                 \n"
@@ -7287,12 +7074,12 @@
       "sub         $0x4,%3                       \n"
       "jge         40b                           \n"
 
-      "49:                                       \n"
+      "49:         \n"
       "add         $0x3,%3                       \n"
       "jl          99f                           \n"
 
       // 1 pixel loop.
-      "91:                                       \n"
+      "91:         \n"
       "movd        (%0),%%xmm3                   \n"
       "lea         0x4(%0),%0                    \n"
       "movdqa      %%xmm3,%%xmm0                 \n"
@@ -7315,7 +7102,7 @@
       "lea         0x4(%2),%2                    \n"
       "sub         $0x1,%3                       \n"
       "jge         91b                           \n"
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(src_argb),     // %0
         "+r"(src_argb1),    // %1
         "+r"(dst_argb),     // %2
@@ -7352,7 +7139,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%2),%%xmm0                   \n"
       "punpcklbw   %%xmm0,%%xmm0                 \n"
       "pxor        %%xmm5,%%xmm0                 \n"
@@ -7404,7 +7191,7 @@
 
       // 32 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%2),%%ymm0                   \n"
       "vpunpckhbw  %%ymm0,%%ymm0,%%ymm3          \n"
       "vpunpcklbw  %%ymm0,%%ymm0,%%ymm0          \n"
@@ -7427,7 +7214,7 @@
       "lea         0x20(%2),%2                   \n"
       "sub         $0x20,%4                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src0),   // %0
         "+r"(src1),   // %1
         "+r"(alpha),  // %2
@@ -7460,7 +7247,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm6                   \n"
       "movdqa      %%xmm6,%%xmm0                 \n"
       "movdqa      %%xmm6,%%xmm1                 \n"
@@ -7515,7 +7302,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm6                   \n"
       "vpunpcklbw  %%ymm5,%%ymm6,%%ymm0          \n"
       "vpunpckhbw  %%ymm5,%%ymm6,%%ymm1          \n"
@@ -7534,7 +7321,7 @@
       "lea         0x20(%0),%0                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),              // %0
         "+r"(dst_argb),              // %1
         "+r"(width)                  // %2
@@ -7553,7 +7340,7 @@
   asm volatile(
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movzb       0x03(%0),%3                   \n"
       "punpcklbw   %%xmm0,%%xmm0                 \n"
@@ -7604,7 +7391,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       // replace VPGATHER
       "movzb       0x03(%0),%3                   \n"
       "vmovd       0x00(%4,%3,4),%%xmm0          \n"
@@ -7645,7 +7432,7 @@
       "lea         0x20(%0),%0                   \n"
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),                 // %0
         "+r"(dst_argb),                 // %1
         "+r"(width),                    // %2
@@ -7666,7 +7453,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "psubb       %%xmm5,%%xmm0                 \n"
@@ -7729,7 +7516,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm6               \n"
       "pmaddubsw   %%xmm2,%%xmm0                 \n"
@@ -7792,7 +7579,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm7               \n"
       "pmaddubsw   %%xmm2,%%xmm0                 \n"
@@ -7864,7 +7651,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "punpcklbw   %%xmm5,%%xmm0                 \n"
       "pmulhuw     %%xmm2,%%xmm0                 \n"
@@ -7906,7 +7693,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
@@ -7935,36 +7722,34 @@
                           const uint8_t* src_argb1,
                           uint8_t* dst_argb,
                           int width) {
-  asm volatile(
+  asm volatile("pxor        %%xmm5,%%xmm5                 \n"
 
-      "pxor        %%xmm5,%%xmm5                 \n"
-
-      // 4 pixel loop.
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "lea         0x10(%0),%0                   \n"
-      "movdqu      (%1),%%xmm2                   \n"
-      "lea         0x10(%1),%1                   \n"
-      "movdqu      %%xmm0,%%xmm1                 \n"
-      "movdqu      %%xmm2,%%xmm3                 \n"
-      "punpcklbw   %%xmm0,%%xmm0                 \n"
-      "punpckhbw   %%xmm1,%%xmm1                 \n"
-      "punpcklbw   %%xmm5,%%xmm2                 \n"
-      "punpckhbw   %%xmm5,%%xmm3                 \n"
-      "pmulhuw     %%xmm2,%%xmm0                 \n"
-      "pmulhuw     %%xmm3,%%xmm1                 \n"
-      "packuswb    %%xmm1,%%xmm0                 \n"
-      "movdqu      %%xmm0,(%2)                   \n"
-      "lea         0x10(%2),%2                   \n"
-      "sub         $0x4,%3                       \n"
-      "jg          1b                            \n"
-      : "+r"(src_argb),   // %0
-        "+r"(src_argb1),  // %1
-        "+r"(dst_argb),   // %2
-        "+r"(width)       // %3
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
+               // 4 pixel loop.
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "lea         0x10(%0),%0                   \n"
+               "movdqu      (%1),%%xmm2                   \n"
+               "lea         0x10(%1),%1                   \n"
+               "movdqu      %%xmm0,%%xmm1                 \n"
+               "movdqu      %%xmm2,%%xmm3                 \n"
+               "punpcklbw   %%xmm0,%%xmm0                 \n"
+               "punpckhbw   %%xmm1,%%xmm1                 \n"
+               "punpcklbw   %%xmm5,%%xmm2                 \n"
+               "punpckhbw   %%xmm5,%%xmm3                 \n"
+               "pmulhuw     %%xmm2,%%xmm0                 \n"
+               "pmulhuw     %%xmm3,%%xmm1                 \n"
+               "packuswb    %%xmm1,%%xmm0                 \n"
+               "movdqu      %%xmm0,(%2)                   \n"
+               "lea         0x10(%2),%2                   \n"
+               "sub         $0x4,%3                       \n"
+               "jg          1b                            \n"
+               : "+r"(src_argb),   // %0
+                 "+r"(src_argb1),  // %1
+                 "+r"(dst_argb),   // %2
+                 "+r"(width)       // %3
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
 }
 #endif  // HAS_ARGBMULTIPLYROW_SSE2
 
@@ -7974,35 +7759,33 @@
                           const uint8_t* src_argb1,
                           uint8_t* dst_argb,
                           int width) {
-  asm volatile(
+  asm volatile("vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
 
-      "vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
-
-      // 4 pixel loop.
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm1                   \n"
-      "lea         0x20(%0),%0                   \n"
-      "vmovdqu     (%1),%%ymm3                   \n"
-      "lea         0x20(%1),%1                   \n"
-      "vpunpcklbw  %%ymm1,%%ymm1,%%ymm0          \n"
-      "vpunpckhbw  %%ymm1,%%ymm1,%%ymm1          \n"
-      "vpunpcklbw  %%ymm5,%%ymm3,%%ymm2          \n"
-      "vpunpckhbw  %%ymm5,%%ymm3,%%ymm3          \n"
-      "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n"
-      "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n"
-      "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"
-      "vmovdqu     %%ymm0,(%2)                   \n"
-      "lea         0x20(%2),%2                   \n"
-      "sub         $0x8,%3                       \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_argb),   // %0
-        "+r"(src_argb1),  // %1
-        "+r"(dst_argb),   // %2
-        "+r"(width)       // %3
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
+               // 4 pixel loop.
+               LABELALIGN
+               "1:          \n"
+               "vmovdqu     (%0),%%ymm1                   \n"
+               "lea         0x20(%0),%0                   \n"
+               "vmovdqu     (%1),%%ymm3                   \n"
+               "lea         0x20(%1),%1                   \n"
+               "vpunpcklbw  %%ymm1,%%ymm1,%%ymm0          \n"
+               "vpunpckhbw  %%ymm1,%%ymm1,%%ymm1          \n"
+               "vpunpcklbw  %%ymm5,%%ymm3,%%ymm2          \n"
+               "vpunpckhbw  %%ymm5,%%ymm3,%%ymm3          \n"
+               "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n"
+               "vpmulhuw    %%ymm3,%%ymm1,%%ymm1          \n"
+               "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"
+               "vmovdqu     %%ymm0,(%2)                   \n"
+               "lea         0x20(%2),%2                   \n"
+               "sub         $0x8,%3                       \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_argb),   // %0
+                 "+r"(src_argb1),  // %1
+                 "+r"(dst_argb),   // %2
+                 "+r"(width)       // %3
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5");
 }
 #endif  // HAS_ARGBMULTIPLYROW_AVX2
 
@@ -8015,7 +7798,7 @@
   asm volatile(
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqu      (%1),%%xmm1                   \n"
@@ -8043,7 +7826,7 @@
   asm volatile(
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "lea         0x20(%0),%0                   \n"
       "vpaddusb    (%1),%%ymm0,%%ymm0            \n"
@@ -8052,7 +7835,7 @@
       "lea         0x20(%2),%2                   \n"
       "sub         $0x8,%3                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
         "+r"(dst_argb),   // %2
@@ -8071,7 +7854,7 @@
   asm volatile(
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqu      (%1),%%xmm1                   \n"
@@ -8099,7 +7882,7 @@
   asm volatile(
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "lea         0x20(%0),%0                   \n"
       "vpsubusb    (%1),%%ymm0,%%ymm0            \n"
@@ -8108,7 +7891,7 @@
       "lea         0x20(%2),%2                   \n"
       "sub         $0x8,%3                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
         "+r"(dst_argb),   // %2
@@ -8136,7 +7919,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"
       "movq        0x2(%0),%%xmm1                \n"
       "punpcklbw   %%xmm5,%%xmm0                 \n"
@@ -8189,7 +7972,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"
       "movq        0x00(%0,%1,1),%%xmm1          \n"
       "punpcklbw   %%xmm5,%%xmm0                 \n"
@@ -8242,7 +8025,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%1,1),%%xmm1          \n"
       "lea         0x10(%0),%0                   \n"
@@ -8289,7 +8072,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%1,1),%%xmm1          \n"
       "lea         0x10(%0),%0                   \n"
@@ -8323,7 +8106,7 @@
 
       // 8 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%1,1),%%xmm1          \n"
       "lea         0x10(%0),%0                   \n"
@@ -8375,7 +8158,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "40:                                       \n"
+      "40:         \n"
       "movdqu      (%0),%%xmm2                   \n"
       "lea         0x10(%0),%0                   \n"
       "movdqa      %%xmm2,%%xmm4                 \n"
@@ -8408,13 +8191,13 @@
       "sub         $0x4,%3                       \n"
       "jge         40b                           \n"
 
-      "49:                                       \n"
+      "49:         \n"
       "add         $0x3,%3                       \n"
       "jl          19f                           \n"
 
       // 1 pixel loop.
       LABELALIGN
-      "10:                                       \n"
+      "10:         \n"
       "movd        (%0),%%xmm2                   \n"
       "lea         0x4(%0),%0                    \n"
       "punpcklbw   %%xmm1,%%xmm2                 \n"
@@ -8428,7 +8211,7 @@
       "sub         $0x1,%3                       \n"
       "jge         10b                           \n"
 
-      "19:                                       \n"
+      "19:         \n"
       : "+r"(row),              // %0
         "+r"(cumsum),           // %1
         "+r"(previous_cumsum),  // %2
@@ -8466,7 +8249,7 @@
 
       // 4 pixel small loop.
       LABELALIGN
-      "4:                                        \n"
+      "4:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm2               \n"
@@ -8498,7 +8281,7 @@
 
       // 4 pixel loop
       LABELALIGN
-      "40:                                       \n"
+      "40:         \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x20(%0),%%xmm2               \n"
@@ -8537,13 +8320,13 @@
       "sub         $0x4,%3                       \n"
       "jge         40b                           \n"
 
-      "49:                                       \n"
+      "49:         \n"
       "add         $0x3,%3                       \n"
       "jl          19f                           \n"
 
       // 1 pixel loop
       LABELALIGN
-      "10:                                       \n"
+      "10:         \n"
       "movdqu      (%0),%%xmm0                   \n"
       "psubd       0x00(%0,%4,4),%%xmm0          \n"
       "lea         0x10(%0),%0                   \n"
@@ -8559,7 +8342,7 @@
       "lea         0x4(%2),%2                    \n"
       "sub         $0x1,%3                       \n"
       "jge         10b                           \n"
-      "19:                                       \n"
+      "19:         \n"
       : "+r"(topleft),           // %0
         "+r"(botleft),           // %1
         "+r"(dst),               // %2
@@ -8602,7 +8385,7 @@
 
       // 4 pixel loop
       LABELALIGN
-      "40:                                       \n"
+      "40:         \n"
       "cvttps2dq   %%xmm2,%%xmm0                 \n"  // x,y float->int first 2
       "cvttps2dq   %%xmm3,%%xmm1                 \n"  // x,y float->int next 2
       "packssdw    %%xmm1,%%xmm0                 \n"  // x, y as 8 shorts
@@ -8628,13 +8411,13 @@
       "sub         $0x4,%4                       \n"
       "jge         40b                           \n"
 
-      "49:                                       \n"
+      "49:         \n"
       "add         $0x3,%4                       \n"
       "jl          19f                           \n"
 
       // 1 pixel loop
       LABELALIGN
-      "10:                                       \n"
+      "10:         \n"
       "cvttps2dq   %%xmm2,%%xmm0                 \n"
       "packssdw    %%xmm0,%%xmm0                 \n"
       "pmaddwd     %%xmm5,%%xmm0                 \n"
@@ -8645,7 +8428,7 @@
       "lea         0x04(%2),%2                   \n"
       "sub         $0x1,%4                       \n"
       "jge         10b                           \n"
-      "19:                                       \n"
+      "19:         \n"
       : "+r"(src_argb),              // %0
         "+r"(src_argb_stride_temp),  // %1
         "+r"(dst_argb),              // %2
@@ -8685,7 +8468,7 @@
 
       // General purpose row blend.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%1),%%xmm0                   \n"
       "movdqu      0x00(%1,%4,1),%%xmm2          \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
@@ -8710,7 +8493,7 @@
 
       // Blend 50 / 50.
       LABELALIGN
-      "50:                                       \n"
+      "50:         \n"
       "movdqu      (%1),%%xmm0                   \n"
       "movdqu      0x00(%1,%4,1),%%xmm1          \n"
       "pavgb       %%xmm1,%%xmm0                 \n"
@@ -8722,14 +8505,14 @@
 
       // Blend 100 / 0 - Copy row unchanged.
       LABELALIGN
-      "100:                                      \n"
+      "100:        \n"
       "movdqu      (%1),%%xmm0                   \n"
       "movdqu      %%xmm0,0x00(%1,%0,1)          \n"
       "lea         0x10(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),               // %0
         "+r"(src_ptr),               // %1
         "+rm"(width),                // %2
@@ -8766,7 +8549,7 @@
 
       // General purpose row blend.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%1),%%ymm0                   \n"
       "vmovdqu     0x00(%1,%4,1),%%ymm2          \n"
       "vpunpckhbw  %%ymm2,%%ymm0,%%ymm1          \n"
@@ -8788,7 +8571,7 @@
 
       // Blend 50 / 50.
       LABELALIGN
-      "50:                                       \n"
+      "50:         \n"
       "vmovdqu     (%1),%%ymm0                   \n"
       "vpavgb      0x00(%1,%4,1),%%ymm0,%%ymm0   \n"
       "vmovdqu     %%ymm0,0x00(%1,%0,1)          \n"
@@ -8799,15 +8582,15 @@
 
       // Blend 100 / 0 - Copy row unchanged.
       LABELALIGN
-      "100:                                      \n"
+      "100:        \n"
       "vmovdqu     (%1),%%ymm0                   \n"
       "vmovdqu     %%ymm0,0x00(%1,%0,1)          \n"
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          100b                          \n"
 
-      "99:                                       \n"
-      "vzeroupper                                \n"
+      "99:         \n"
+      "vzeroupper  \n"
       : "+r"(dst_ptr),               // %0
         "+r"(src_ptr),               // %1
         "+r"(width),                 // %2
@@ -8823,27 +8606,25 @@
                           uint8_t* dst_argb,
                           const uint8_t* shuffler,
                           int width) {
-  asm volatile(
+  asm volatile("movdqu      (%3),%%xmm5                   \n"
 
-      "movdqu      (%3),%%xmm5                   \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "lea         0x20(%0),%0                   \n"
-      "pshufb      %%xmm5,%%xmm0                 \n"
-      "pshufb      %%xmm5,%%xmm1                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "movdqu      %%xmm1,0x10(%1)               \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x8,%2                       \n"
-      "jg          1b                            \n"
-      : "+r"(src_argb),  // %0
-        "+r"(dst_argb),  // %1
-        "+r"(width)      // %2
-      : "r"(shuffler)    // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x10(%0),%%xmm1               \n"
+               "lea         0x20(%0),%0                   \n"
+               "pshufb      %%xmm5,%%xmm0                 \n"
+               "pshufb      %%xmm5,%%xmm1                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "movdqu      %%xmm1,0x10(%1)               \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x8,%2                       \n"
+               "jg          1b                            \n"
+               : "+r"(src_argb),  // %0
+                 "+r"(dst_argb),  // %1
+                 "+r"(width)      // %2
+               : "r"(shuffler)    // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 #endif  // HAS_ARGBSHUFFLEROW_SSSE3
 
@@ -8853,28 +8634,26 @@
                          uint8_t* dst_argb,
                          const uint8_t* shuffler,
                          int width) {
-  asm volatile(
+  asm volatile("vbroadcastf128 (%3),%%ymm5                \n"
 
-      "vbroadcastf128 (%3),%%ymm5                \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "lea         0x40(%0),%0                   \n"
-      "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "vmovdqu     %%ymm1,0x20(%1)               \n"
-      "lea         0x40(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_argb),  // %0
-        "+r"(dst_argb),  // %1
-        "+r"(width)      // %2
-      : "r"(shuffler)    // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "vmovdqu     (%0),%%ymm0                   \n"
+               "vmovdqu     0x20(%0),%%ymm1               \n"
+               "lea         0x40(%0),%0                   \n"
+               "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
+               "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "vmovdqu     %%ymm1,0x20(%1)               \n"
+               "lea         0x40(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_argb),  // %0
+                 "+r"(dst_argb),  // %1
+                 "+r"(width)      // %2
+               : "r"(shuffler)    // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 #endif  // HAS_ARGBSHUFFLEROW_AVX2
 
@@ -8884,33 +8663,31 @@
                         const uint8_t* src_v,
                         uint8_t* dst_yuy2,
                         int width) {
-  asm volatile(
+  asm volatile("sub         %1,%2                         \n"
 
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movq        (%1),%%xmm2                   \n"
-      "movq        0x00(%1,%2,1),%%xmm1          \n"
-      "add         $0x8,%1                       \n"
-      "punpcklbw   %%xmm1,%%xmm2                 \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "add         $0x10,%0                      \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "punpcklbw   %%xmm2,%%xmm0                 \n"
-      "punpckhbw   %%xmm2,%%xmm1                 \n"
-      "movdqu      %%xmm0,(%3)                   \n"
-      "movdqu      %%xmm1,0x10(%3)               \n"
-      "lea         0x20(%3),%3                   \n"
-      "sub         $0x10,%4                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_y),     // %0
-        "+r"(src_u),     // %1
-        "+r"(src_v),     // %2
-        "+r"(dst_yuy2),  // %3
-        "+rm"(width)     // %4
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+               LABELALIGN
+               "1:          \n"
+               "movq        (%1),%%xmm2                   \n"
+               "movq        0x00(%1,%2,1),%%xmm1          \n"
+               "add         $0x8,%1                       \n"
+               "punpcklbw   %%xmm1,%%xmm2                 \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "add         $0x10,%0                      \n"
+               "movdqa      %%xmm0,%%xmm1                 \n"
+               "punpcklbw   %%xmm2,%%xmm0                 \n"
+               "punpckhbw   %%xmm2,%%xmm1                 \n"
+               "movdqu      %%xmm0,(%3)                   \n"
+               "movdqu      %%xmm1,0x10(%3)               \n"
+               "lea         0x20(%3),%3                   \n"
+               "sub         $0x10,%4                      \n"
+               "jg          1b                            \n"
+               : "+r"(src_y),     // %0
+                 "+r"(src_u),     // %1
+                 "+r"(src_v),     // %2
+                 "+r"(dst_yuy2),  // %3
+                 "+rm"(width)     // %4
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_I422TOYUY2ROW_SSE2
 
@@ -8920,33 +8697,31 @@
                         const uint8_t* src_v,
                         uint8_t* dst_uyvy,
                         int width) {
-  asm volatile(
+  asm volatile("sub         %1,%2                         \n"
 
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movq        (%1),%%xmm2                   \n"
-      "movq        0x00(%1,%2,1),%%xmm1          \n"
-      "add         $0x8,%1                       \n"
-      "punpcklbw   %%xmm1,%%xmm2                 \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqa      %%xmm2,%%xmm1                 \n"
-      "add         $0x10,%0                      \n"
-      "punpcklbw   %%xmm0,%%xmm1                 \n"
-      "punpckhbw   %%xmm0,%%xmm2                 \n"
-      "movdqu      %%xmm1,(%3)                   \n"
-      "movdqu      %%xmm2,0x10(%3)               \n"
-      "lea         0x20(%3),%3                   \n"
-      "sub         $0x10,%4                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_y),     // %0
-        "+r"(src_u),     // %1
-        "+r"(src_v),     // %2
-        "+r"(dst_uyvy),  // %3
-        "+rm"(width)     // %4
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+               LABELALIGN
+               "1:          \n"
+               "movq        (%1),%%xmm2                   \n"
+               "movq        0x00(%1,%2,1),%%xmm1          \n"
+               "add         $0x8,%1                       \n"
+               "punpcklbw   %%xmm1,%%xmm2                 \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqa      %%xmm2,%%xmm1                 \n"
+               "add         $0x10,%0                      \n"
+               "punpcklbw   %%xmm0,%%xmm1                 \n"
+               "punpckhbw   %%xmm0,%%xmm2                 \n"
+               "movdqu      %%xmm1,(%3)                   \n"
+               "movdqu      %%xmm2,0x10(%3)               \n"
+               "lea         0x20(%3),%3                   \n"
+               "sub         $0x10,%4                      \n"
+               "jg          1b                            \n"
+               : "+r"(src_y),     // %0
+                 "+r"(src_u),     // %1
+                 "+r"(src_v),     // %2
+                 "+r"(dst_uyvy),  // %3
+                 "+rm"(width)     // %4
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_I422TOUYVYROW_SSE2
 
@@ -8956,36 +8731,34 @@
                         const uint8_t* src_v,
                         uint8_t* dst_yuy2,
                         int width) {
-  asm volatile(
+  asm volatile("sub         %1,%2                         \n"
 
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vpmovzxbw   (%1),%%ymm1                   \n"
-      "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n"
-      "add         $0x10,%1                      \n"
-      "vpsllw      $0x8,%%ymm2,%%ymm2            \n"
-      "vpor        %%ymm1,%%ymm2,%%ymm2          \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "add         $0x20,%0                      \n"
-      "vpunpcklbw  %%ymm2,%%ymm0,%%ymm1          \n"
-      "vpunpckhbw  %%ymm2,%%ymm0,%%ymm2          \n"
-      "vextractf128 $0x0,%%ymm1,(%3)             \n"
-      "vextractf128 $0x0,%%ymm2,0x10(%3)         \n"
-      "vextractf128 $0x1,%%ymm1,0x20(%3)         \n"
-      "vextractf128 $0x1,%%ymm2,0x30(%3)         \n"
-      "lea         0x40(%3),%3                   \n"
-      "sub         $0x20,%4                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_y),     // %0
-        "+r"(src_u),     // %1
-        "+r"(src_v),     // %2
-        "+r"(dst_yuy2),  // %3
-        "+rm"(width)     // %4
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+               LABELALIGN
+               "1:          \n"
+               "vpmovzxbw   (%1),%%ymm1                   \n"
+               "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n"
+               "add         $0x10,%1                      \n"
+               "vpsllw      $0x8,%%ymm2,%%ymm2            \n"
+               "vpor        %%ymm1,%%ymm2,%%ymm2          \n"
+               "vmovdqu     (%0),%%ymm0                   \n"
+               "add         $0x20,%0                      \n"
+               "vpunpcklbw  %%ymm2,%%ymm0,%%ymm1          \n"
+               "vpunpckhbw  %%ymm2,%%ymm0,%%ymm2          \n"
+               "vextractf128 $0x0,%%ymm1,(%3)             \n"
+               "vextractf128 $0x0,%%ymm2,0x10(%3)         \n"
+               "vextractf128 $0x1,%%ymm1,0x20(%3)         \n"
+               "vextractf128 $0x1,%%ymm2,0x30(%3)         \n"
+               "lea         0x40(%3),%3                   \n"
+               "sub         $0x20,%4                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_y),     // %0
+                 "+r"(src_u),     // %1
+                 "+r"(src_v),     // %2
+                 "+r"(dst_yuy2),  // %3
+                 "+rm"(width)     // %4
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_I422TOYUY2ROW_AVX2
 
@@ -8995,36 +8768,34 @@
                         const uint8_t* src_v,
                         uint8_t* dst_uyvy,
                         int width) {
-  asm volatile(
+  asm volatile("sub         %1,%2                         \n"
 
-      "sub         %1,%2                         \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vpmovzxbw   (%1),%%ymm1                   \n"
-      "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n"
-      "add         $0x10,%1                      \n"
-      "vpsllw      $0x8,%%ymm2,%%ymm2            \n"
-      "vpor        %%ymm1,%%ymm2,%%ymm2          \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "add         $0x20,%0                      \n"
-      "vpunpcklbw  %%ymm0,%%ymm2,%%ymm1          \n"
-      "vpunpckhbw  %%ymm0,%%ymm2,%%ymm2          \n"
-      "vextractf128 $0x0,%%ymm1,(%3)             \n"
-      "vextractf128 $0x0,%%ymm2,0x10(%3)         \n"
-      "vextractf128 $0x1,%%ymm1,0x20(%3)         \n"
-      "vextractf128 $0x1,%%ymm2,0x30(%3)         \n"
-      "lea         0x40(%3),%3                   \n"
-      "sub         $0x20,%4                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_y),     // %0
-        "+r"(src_u),     // %1
-        "+r"(src_v),     // %2
-        "+r"(dst_uyvy),  // %3
-        "+rm"(width)     // %4
-      :
-      : "memory", "cc", "xmm0", "xmm1", "xmm2");
+               LABELALIGN
+               "1:          \n"
+               "vpmovzxbw   (%1),%%ymm1                   \n"
+               "vpmovzxbw   0x00(%1,%2,1),%%ymm2          \n"
+               "add         $0x10,%1                      \n"
+               "vpsllw      $0x8,%%ymm2,%%ymm2            \n"
+               "vpor        %%ymm1,%%ymm2,%%ymm2          \n"
+               "vmovdqu     (%0),%%ymm0                   \n"
+               "add         $0x20,%0                      \n"
+               "vpunpcklbw  %%ymm0,%%ymm2,%%ymm1          \n"
+               "vpunpckhbw  %%ymm0,%%ymm2,%%ymm2          \n"
+               "vextractf128 $0x0,%%ymm1,(%3)             \n"
+               "vextractf128 $0x0,%%ymm2,0x10(%3)         \n"
+               "vextractf128 $0x1,%%ymm1,0x20(%3)         \n"
+               "vextractf128 $0x1,%%ymm2,0x30(%3)         \n"
+               "lea         0x40(%3),%3                   \n"
+               "sub         $0x20,%4                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_y),     // %0
+                 "+r"(src_u),     // %1
+                 "+r"(src_v),     // %2
+                 "+r"(dst_uyvy),  // %3
+                 "+rm"(width)     // %4
+               :
+               : "memory", "cc", "xmm0", "xmm1", "xmm2");
 }
 #endif  // HAS_I422TOUYVYROW_AVX2
 
@@ -9033,54 +8804,53 @@
                             uint8_t* dst_argb,
                             const float* poly,
                             int width) {
-  asm volatile(
+  asm volatile("pxor        %%xmm3,%%xmm3                 \n"
 
-      "pxor        %%xmm3,%%xmm3                 \n"
-
-      // 2 pixel loop.
-      LABELALIGN
-      "1:                                        \n"
-      "movq        (%0),%%xmm0                   \n"
-      "lea         0x8(%0),%0                    \n"
-      "punpcklbw   %%xmm3,%%xmm0                 \n"
-      "movdqa      %%xmm0,%%xmm4                 \n"
-      "punpcklwd   %%xmm3,%%xmm0                 \n"
-      "punpckhwd   %%xmm3,%%xmm4                 \n"
-      "cvtdq2ps    %%xmm0,%%xmm0                 \n"
-      "cvtdq2ps    %%xmm4,%%xmm4                 \n"
-      "movdqa      %%xmm0,%%xmm1                 \n"
-      "movdqa      %%xmm4,%%xmm5                 \n"
-      "mulps       0x10(%3),%%xmm0               \n"
-      "mulps       0x10(%3),%%xmm4               \n"
-      "addps       (%3),%%xmm0                   \n"
-      "addps       (%3),%%xmm4                   \n"
-      "movdqa      %%xmm1,%%xmm2                 \n"
-      "movdqa      %%xmm5,%%xmm6                 \n"
-      "mulps       %%xmm1,%%xmm2                 \n"
-      "mulps       %%xmm5,%%xmm6                 \n"
-      "mulps       %%xmm2,%%xmm1                 \n"
-      "mulps       %%xmm6,%%xmm5                 \n"
-      "mulps       0x20(%3),%%xmm2               \n"
-      "mulps       0x20(%3),%%xmm6               \n"
-      "mulps       0x30(%3),%%xmm1               \n"
-      "mulps       0x30(%3),%%xmm5               \n"
-      "addps       %%xmm2,%%xmm0                 \n"
-      "addps       %%xmm6,%%xmm4                 \n"
-      "addps       %%xmm1,%%xmm0                 \n"
-      "addps       %%xmm5,%%xmm4                 \n"
-      "cvttps2dq   %%xmm0,%%xmm0                 \n"
-      "cvttps2dq   %%xmm4,%%xmm4                 \n"
-      "packuswb    %%xmm4,%%xmm0                 \n"
-      "packuswb    %%xmm0,%%xmm0                 \n"
-      "movq        %%xmm0,(%1)                   \n"
-      "lea         0x8(%1),%1                    \n"
-      "sub         $0x2,%2                       \n"
-      "jg          1b                            \n"
-      : "+r"(src_argb),  // %0
-        "+r"(dst_argb),  // %1
-        "+r"(width)      // %2
-      : "r"(poly)        // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
+               // 2 pixel loop.
+               LABELALIGN
+               "1:          \n"
+               "movq        (%0),%%xmm0                   \n"
+               "lea         0x8(%0),%0                    \n"
+               "punpcklbw   %%xmm3,%%xmm0                 \n"
+               "movdqa      %%xmm0,%%xmm4                 \n"
+               "punpcklwd   %%xmm3,%%xmm0                 \n"
+               "punpckhwd   %%xmm3,%%xmm4                 \n"
+               "cvtdq2ps    %%xmm0,%%xmm0                 \n"
+               "cvtdq2ps    %%xmm4,%%xmm4                 \n"
+               "movdqa      %%xmm0,%%xmm1                 \n"
+               "movdqa      %%xmm4,%%xmm5                 \n"
+               "mulps       0x10(%3),%%xmm0               \n"
+               "mulps       0x10(%3),%%xmm4               \n"
+               "addps       (%3),%%xmm0                   \n"
+               "addps       (%3),%%xmm4                   \n"
+               "movdqa      %%xmm1,%%xmm2                 \n"
+               "movdqa      %%xmm5,%%xmm6                 \n"
+               "mulps       %%xmm1,%%xmm2                 \n"
+               "mulps       %%xmm5,%%xmm6                 \n"
+               "mulps       %%xmm2,%%xmm1                 \n"
+               "mulps       %%xmm6,%%xmm5                 \n"
+               "mulps       0x20(%3),%%xmm2               \n"
+               "mulps       0x20(%3),%%xmm6               \n"
+               "mulps       0x30(%3),%%xmm1               \n"
+               "mulps       0x30(%3),%%xmm5               \n"
+               "addps       %%xmm2,%%xmm0                 \n"
+               "addps       %%xmm6,%%xmm4                 \n"
+               "addps       %%xmm1,%%xmm0                 \n"
+               "addps       %%xmm5,%%xmm4                 \n"
+               "cvttps2dq   %%xmm0,%%xmm0                 \n"
+               "cvttps2dq   %%xmm4,%%xmm4                 \n"
+               "packuswb    %%xmm4,%%xmm0                 \n"
+               "packuswb    %%xmm0,%%xmm0                 \n"
+               "movq        %%xmm0,(%1)                   \n"
+               "lea         0x8(%1),%1                    \n"
+               "sub         $0x2,%2                       \n"
+               "jg          1b                            \n"
+               : "+r"(src_argb),  // %0
+                 "+r"(dst_argb),  // %1
+                 "+r"(width)      // %2
+               : "r"(poly)        // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
+                 "xmm6");
 }
 #endif  // HAS_ARGBPOLYNOMIALROW_SSE2
 
@@ -9097,7 +8867,7 @@
 
       // 2 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vpmovzxbd   (%0),%%ymm0                   \n"  // 2 ARGB pixels
       "lea         0x8(%0),%0                    \n"
       "vcvtdq2ps   %%ymm0,%%ymm0                 \n"  // X 8 floats
@@ -9115,7 +8885,7 @@
       "lea         0x8(%1),%1                    \n"
       "sub         $0x2,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_argb),  // %0
         "+r"(dst_argb),  // %1
         "+r"(width)      // %2
@@ -9140,7 +8910,7 @@
 
       // 16 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm2                   \n"  // 8 shorts
       "add         $0x10,%0                      \n"
       "movdqa      %%xmm2,%%xmm3                 \n"
@@ -9177,7 +8947,7 @@
 
       // 16 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm2                   \n"  // 16 shorts
       "add         $0x20,%0                      \n"
       "vpunpckhwd  %%ymm5,%%ymm2,%%ymm3          \n"  // mutates
@@ -9193,14 +8963,14 @@
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
 
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
 #if defined(__x86_64__)
       : "x"(scale)  // %3
 #else
-      : "m"(scale)            // %3
+      : "m"(scale)    // %3
 #endif
       : "memory", "cc", "xmm2", "xmm3", "xmm4", "xmm5");
 }
@@ -9217,7 +8987,7 @@
 
       // 16 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vpmovzxwd   (%0),%%ymm2                   \n"  // 16 shorts -> 16 ints
       "vpmovzxwd   0x10(%0),%%ymm3               \n"
       "vcvtdq2ps   %%ymm2,%%ymm2                 \n"
@@ -9231,14 +9001,14 @@
       "add         $0x20,%0                      \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
 #if defined(__x86_64__)
       : "x"(scale)  // %3
 #else
-      : "m"(scale)            // %3
+      : "m"(scale)    // %3
 #endif
       : "memory", "cc", "xmm2", "xmm3", "xmm4");
 }
@@ -9250,7 +9020,7 @@
       "sub         %0,%1                         \n"
       // 16 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vpmovzxwd   (%0),%%ymm2                   \n"  // 16 shorts -> 16 ints
       "vpmovzxwd   0x10(%0),%%ymm3               \n"
       "vcvtdq2ps   %%ymm2,%%ymm2                 \n"
@@ -9262,7 +9032,7 @@
       "add         $0x20,%0                      \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src),   // %0
         "+r"(dst),   // %1
         "+r"(width)  // %2
@@ -9280,7 +9050,7 @@
   asm volatile(
       // 1 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movzb       (%0),%1                       \n"
       "lea         0x4(%0),%0                    \n"
       "movzb       0x00(%3,%1,4),%1              \n"
@@ -9313,7 +9083,7 @@
   asm volatile(
       // 1 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movzb       (%0),%1                       \n"
       "lea         0x4(%0),%0                    \n"
       "movzb       0x00(%3,%1,4),%1              \n"
@@ -9352,7 +9122,7 @@
 
       // 4 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%2),%%xmm0                   \n"
       "pmaddubsw   %%xmm3,%%xmm0                 \n"
       "phaddw      %%xmm0,%%xmm0                 \n"
@@ -9452,7 +9222,7 @@
       "movdqa      (%4),%%xmm4                   \n"  // 3 shuffler constants
       "movdqa      16(%4),%%xmm5                 \n"
       "movdqa      32(%4),%%xmm6                 \n"
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm2                   \n"  // load 16 Y values
       "movdqu      (%0,%1),%%xmm3                \n"  // load 8 VU values
       "lea         16(%0),%0                     \n"
@@ -9491,7 +9261,7 @@
       "vbroadcastf128 16(%4),%%ymm5              \n"
       "vbroadcastf128 32(%4),%%ymm6              \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm2                   \n"  // load 32 Y values
       "vmovdqu     (%0,%1),%%ymm3                \n"  // load 16 VU values
       "lea         32(%0),%0                     \n"
@@ -9510,7 +9280,7 @@
       "lea         96(%2),%2                     \n"
       "sub         $32,%3                        \n"  // 32 pixels per loop
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_y),            // %0
         "+r"(src_vu),           // %1
         "+r"(dst_yuv24),        // %2
@@ -9538,7 +9308,7 @@
       "vmovdqa     (%4),%%ymm4                   \n"  // 3 shuffler constants
       "vmovdqa     32(%4),%%ymm5                 \n"
       "vmovdqa     64(%4),%%ymm6                 \n" LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm2                   \n"  // load 32 Y values
       "vmovdqu     (%0,%1),%%ymm3                \n"  // load 16 VU values
       "lea         32(%0),%0                     \n"
@@ -9553,7 +9323,7 @@
       "lea         96(%2),%2                     \n"
       "sub         $32,%3                        \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_y),         // %0
         "+r"(src_vu),        // %1
         "+r"(dst_yuv24),     // %2
@@ -9572,54 +9342,50 @@
 
 // Convert UV plane of NV12 to VU of NV21.
 void SwapUVRow_SSSE3(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
-  asm volatile(
+  asm volatile("movdqu      %3,%%xmm5                     \n"
 
-      "movdqu      %3,%%xmm5                     \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm0                   \n"
-      "movdqu      0x10(%0),%%xmm1               \n"
-      "lea         0x20(%0),%0                   \n"
-      "pshufb      %%xmm5,%%xmm0                 \n"
-      "pshufb      %%xmm5,%%xmm1                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "movdqu      %%xmm1,0x10(%1)               \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
-      : "+r"(src_uv),        // %0
-        "+r"(dst_vu),        // %1
-        "+r"(width)          // %2
-      : "m"(kShuffleUVToVU)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "movdqu      (%0),%%xmm0                   \n"
+               "movdqu      0x10(%0),%%xmm1               \n"
+               "lea         0x20(%0),%0                   \n"
+               "pshufb      %%xmm5,%%xmm0                 \n"
+               "pshufb      %%xmm5,%%xmm1                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "movdqu      %%xmm1,0x10(%1)               \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
+               : "+r"(src_uv),        // %0
+                 "+r"(dst_vu),        // %1
+                 "+r"(width)          // %2
+               : "m"(kShuffleUVToVU)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 #endif  // HAS_SWAPUVROW_SSSE3
 
 #ifdef HAS_SWAPUVROW_AVX2
 void SwapUVRow_AVX2(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
-  asm volatile(
+  asm volatile("vbroadcastf128 %3,%%ymm5                  \n"
 
-      "vbroadcastf128 %3,%%ymm5                  \n"
-
-      LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm0                   \n"
-      "vmovdqu     0x20(%0),%%ymm1               \n"
-      "lea         0x40(%0),%0                   \n"
-      "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
-      "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "vmovdqu     %%ymm1,0x20(%1)               \n"
-      "lea         0x40(%1),%1                   \n"
-      "sub         $0x20,%2                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
-      : "+r"(src_uv),        // %0
-        "+r"(dst_vu),        // %1
-        "+r"(width)          // %2
-      : "m"(kShuffleUVToVU)  // %3
-      : "memory", "cc", "xmm0", "xmm1", "xmm5");
+               LABELALIGN
+               "1:          \n"
+               "vmovdqu     (%0),%%ymm0                   \n"
+               "vmovdqu     0x20(%0),%%ymm1               \n"
+               "lea         0x40(%0),%0                   \n"
+               "vpshufb     %%ymm5,%%ymm0,%%ymm0          \n"
+               "vpshufb     %%ymm5,%%ymm1,%%ymm1          \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "vmovdqu     %%ymm1,0x20(%1)               \n"
+               "lea         0x40(%1),%1                   \n"
+               "sub         $0x20,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
+               : "+r"(src_uv),        // %0
+                 "+r"(dst_vu),        // %1
+                 "+r"(width)          // %2
+               : "m"(kShuffleUVToVU)  // %3
+               : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 #endif  // HAS_SWAPUVROW_AVX2
 
@@ -9630,13 +9396,12 @@
                           uint8_t* dst_uv,
                           int width) {
   asm volatile(
-      "pcmpeqb     %%xmm4,%%xmm4                 \n"
-      "psrlw       $0xf,%%xmm4                   \n"
-      "packuswb    %%xmm4,%%xmm4                 \n"
+      "pcmpeqb     %%xmm4,%%xmm4                 \n"  // 0x0101
+      "pabsb       %%xmm4,%%xmm4                 \n"
       "pxor        %%xmm5,%%xmm5                 \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // load 16 U values
       "movdqu      (%1),%%xmm1                   \n"  // load 16 V values
       "movdqu      0(%0,%4,1),%%xmm2             \n"  // 16 from next row
@@ -9677,12 +9442,11 @@
                          int width) {
   asm volatile(
       "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"
-      "vpsrlw      $0xf,%%ymm4,%%ymm4            \n"
-      "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpabsb      %%ymm4,%%ymm4                 \n"
       "vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // load 32 U values
       "vmovdqu     (%1),%%ymm1                   \n"  // load 32 V values
       "vmovdqu     0(%0,%4,1),%%ymm2             \n"  // 32 from next row
@@ -9706,7 +9470,7 @@
       "lea         0x20(%2),%2                   \n"
       "sub         $0x20,%3                      \n"  // 32 src pixels per loop
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_u),                    // %0
         "+r"(src_v),                    // %1
         "+r"(dst_uv),                   // %2
@@ -9721,7 +9485,7 @@
       "pxor        %%xmm1,%%xmm1                 \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movd        (%0),%%xmm0                   \n"  // load float
       "maxss       %%xmm1, %%xmm0                \n"  // clamp to zero
       "add         4, %0                         \n"
@@ -9736,6 +9500,45 @@
       : "memory", "cc", "xmm0", "xmm1");
 }
 
+#ifdef HAS_CONVERT16TO8ROW_AVX2
+void Convert8To8Row_AVX2(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width) {
+  asm volatile(
+      "sub         %0,%1                         \n"
+      "vmovd       %3,%%xmm2                     \n"
+      "vmovd       %4,%%xmm3                     \n"
+      "vpbroadcastw %%xmm2,%%ymm2                \n"
+      "vpbroadcastb %%xmm3,%%ymm3                \n"
+      "vpxor       %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpsllw      $8,%%ymm2,%%ymm2              \n"
+
+      // 32 pixels per loop.
+      LABELALIGN
+      "1:          \n"
+      "vmovdqu     (%0),%%ymm0                   \n"
+      "vpunpckhbw  %%ymm4,%%ymm0,%%ymm1          \n"  // mutates
+      "vpunpcklbw  %%ymm4,%%ymm0,%%ymm0          \n"
+      "vpmulhuw    %%ymm2,%%ymm0,%%ymm0          \n"
+      "vpmulhuw    %%ymm2,%%ymm1,%%ymm1          \n"
+      "vpackuswb   %%ymm1,%%ymm0,%%ymm0          \n"  // unmutates
+      "vpaddb      %%ymm3,%%ymm0,%%ymm0          \n"
+      "vmovdqu     %%ymm0,(%0,%1)                \n"
+      "add         $0x20,%0                      \n"
+      "sub         $0x20,%2                      \n"
+      "jg          1b                            \n"
+      "vzeroupper  \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale),   // %3
+        "r"(bias)     // %4
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4");
+}
+#endif  // HAS_CONVERT16TO8ROW_AVX2
+
 #endif  // defined(__x86_64__) || defined(__i386__)
 
 #ifdef __cplusplus
diff --git a/source/row_lasx.cc b/source/row_lasx.cc
index be85022..3613b0a 100644
--- a/source/row_lasx.cc
+++ b/source/row_lasx.cc
@@ -1148,24 +1148,26 @@
   __m256i b, g, r, a, dst0, dst1;
   __m256i control = {0x0005000100040000, 0x0007000300060002, 0x0005000100040000,
                      0x0007000300060002};
+  __m256i zero = __lasx_xvldi(0);
+  __m256i const_add = __lasx_xvldi(0x8ff);
 
   for (x = 0; x < len; x++) {
     DUP2_ARG2(__lasx_xvld, src_argb, 0, src_argb, 32, src0, src1);
     tmp0 = __lasx_xvpickev_b(src1, src0);
     tmp1 = __lasx_xvpickod_b(src1, src0);
-    b = __lasx_xvpackev_b(tmp0, tmp0);
-    r = __lasx_xvpackod_b(tmp0, tmp0);
-    g = __lasx_xvpackev_b(tmp1, tmp1);
-    a = __lasx_xvpackod_b(tmp1, tmp1);
-    reg0 = __lasx_xvmulwev_w_hu(b, a);
-    reg1 = __lasx_xvmulwod_w_hu(b, a);
-    reg2 = __lasx_xvmulwev_w_hu(r, a);
-    reg3 = __lasx_xvmulwod_w_hu(r, a);
-    reg4 = __lasx_xvmulwev_w_hu(g, a);
-    reg5 = __lasx_xvmulwod_w_hu(g, a);
-    reg0 = __lasx_xvssrani_h_w(reg1, reg0, 24);
-    reg2 = __lasx_xvssrani_h_w(reg3, reg2, 24);
-    reg4 = __lasx_xvssrani_h_w(reg5, reg4, 24);
+    b = __lasx_xvpackev_b(zero, tmp0);
+    r = __lasx_xvpackod_b(zero, tmp0);
+    g = __lasx_xvpackev_b(zero, tmp1);
+    a = __lasx_xvpackod_b(zero, tmp1);
+    reg0 = __lasx_xvmaddwev_w_hu(const_add, b, a);
+    reg1 = __lasx_xvmaddwod_w_hu(const_add, b, a);
+    reg2 = __lasx_xvmaddwev_w_hu(const_add, r, a);
+    reg3 = __lasx_xvmaddwod_w_hu(const_add, r, a);
+    reg4 = __lasx_xvmaddwev_w_hu(const_add, g, a);
+    reg5 = __lasx_xvmaddwod_w_hu(const_add, g, a);
+    reg0 = __lasx_xvssrani_h_w(reg1, reg0, 8);
+    reg2 = __lasx_xvssrani_h_w(reg3, reg2, 8);
+    reg4 = __lasx_xvssrani_h_w(reg5, reg4, 8);
     reg0 = __lasx_xvshuf_h(control, reg0, reg0);
     reg2 = __lasx_xvshuf_h(control, reg2, reg2);
     reg4 = __lasx_xvshuf_h(control, reg4, reg4);
diff --git a/source/row_lsx.cc b/source/row_lsx.cc
index fa088c9..10546a9 100644
--- a/source/row_lsx.cc
+++ b/source/row_lsx.cc
@@ -1102,24 +1102,26 @@
   __m128i reg0, reg1, reg2, reg3, reg4, reg5;
   __m128i b, g, r, a, dst0, dst1;
   __m128i control = {0x0005000100040000, 0x0007000300060002};
+  __m128i zero = __lsx_vldi(0);
+  __m128i const_add = __lsx_vldi(0x8ff);
 
   for (x = 0; x < len; x++) {
     DUP2_ARG2(__lsx_vld, src_argb, 0, src_argb, 16, src0, src1);
     tmp0 = __lsx_vpickev_b(src1, src0);
     tmp1 = __lsx_vpickod_b(src1, src0);
-    b = __lsx_vpackev_b(tmp0, tmp0);
-    r = __lsx_vpackod_b(tmp0, tmp0);
-    g = __lsx_vpackev_b(tmp1, tmp1);
-    a = __lsx_vpackod_b(tmp1, tmp1);
-    reg0 = __lsx_vmulwev_w_hu(b, a);
-    reg1 = __lsx_vmulwod_w_hu(b, a);
-    reg2 = __lsx_vmulwev_w_hu(r, a);
-    reg3 = __lsx_vmulwod_w_hu(r, a);
-    reg4 = __lsx_vmulwev_w_hu(g, a);
-    reg5 = __lsx_vmulwod_w_hu(g, a);
-    reg0 = __lsx_vssrani_h_w(reg1, reg0, 24);
-    reg2 = __lsx_vssrani_h_w(reg3, reg2, 24);
-    reg4 = __lsx_vssrani_h_w(reg5, reg4, 24);
+    b = __lsx_vpackev_b(zero, tmp0);
+    r = __lsx_vpackod_b(zero, tmp0);
+    g = __lsx_vpackev_b(zero, tmp1);
+    a = __lsx_vpackod_b(zero, tmp1);
+    reg0 = __lsx_vmaddwev_w_hu(const_add, b, a);
+    reg1 = __lsx_vmaddwod_w_hu(const_add, b, a);
+    reg2 = __lsx_vmaddwev_w_hu(const_add, r, a);
+    reg3 = __lsx_vmaddwod_w_hu(const_add, r, a);
+    reg4 = __lsx_vmaddwev_w_hu(const_add, g, a);
+    reg5 = __lsx_vmaddwod_w_hu(const_add, g, a);
+    reg0 = __lsx_vssrani_h_w(reg1, reg0, 8);
+    reg2 = __lsx_vssrani_h_w(reg3, reg2, 8);
+    reg4 = __lsx_vssrani_h_w(reg5, reg4, 8);
     reg0 = __lsx_vshuf_h(control, reg0, reg0);
     reg2 = __lsx_vshuf_h(control, reg2, reg2);
     reg4 = __lsx_vshuf_h(control, reg4, reg4);
diff --git a/source/row_neon.cc b/source/row_neon.cc
index 31142a9..9dff94e 100644
--- a/source/row_neon.cc
+++ b/source/row_neon.cc
@@ -143,9 +143,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV444 YUVTORGB
-          RGBTORGB8
-      "subs        %[width], %[width], #8        \n"
+      "1:          \n"  //
+      READYUV444
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -166,9 +166,9 @@
                          int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV444 YUVTORGB
-          RGBTORGB8
-      "subs        %[width], %[width], #8        \n"
+      "1:          \n"  //
+      READYUV444
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vst3.8      {d0, d2, d4}, [%[dst_rgb24]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -190,9 +190,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %[width], %[width], #8        \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -214,10 +214,10 @@
                              int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV444 YUVTORGB
-          RGBTORGB8
+      "1:          \n"  //
+      READYUV444
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vld1.8      {d6}, [%[src_a]]!             \n"
-      "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -240,10 +240,10 @@
                              int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vld1.8      {d6}, [%[src_a]]!             \n"
-      "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -266,9 +266,10 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV422 YUVTORGB
-      RGBTORGB8 "subs        %[width], %[width], #8        \n" STORERGBA
-      "bgt         1b                            \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
+          STORERGBA "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
         [src_u] "+r"(src_u),                               // %[src_u]
         [src_v] "+r"(src_v),                               // %[src_v]
@@ -288,9 +289,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %[width], %[width], #8        \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vst3.8      {d0, d2, d4}, [%[dst_rgb24]]! \n"
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -319,8 +320,10 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV422 YUVTORGB
-      RGBTORGB8 "subs        %[width], %[width], #8        \n" ARGBTORGB565
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
+          ARGBTORGB565
       "vst1.8      {q2}, [%[dst_rgb565]]!        \n"  // store 8 pixels RGB565.
       "bgt         1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -350,9 +353,9 @@
                             int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %[width], %[width], #8        \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %[width], %[width], #8        \n" YUVTORGB RGBTORGB8
       "vmov.u8     d6, #0xff                     \n" ARGBTOARGB1555
       "vst1.8      {q3}, [%[dst_argb1555]]!      \n"  // store 8 pixels RGB1555.
       "bgt         1b                            \n"
@@ -385,8 +388,8 @@
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
       "vmov.u8     d7, #0x0f                     \n"  // vbic bits to clear
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
+      "1:          \n"                                //
+      READYUV422 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n" ARGBTOARGB4444
       "vst1.8      {q0}, [%[dst_argb4444]]!      \n"  // store 8 pixels
       "bgt         1b                            \n"
@@ -407,8 +410,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUV400 YUVTORGB
-          RGBTORGB8
+      "1:          \n"  //
+      READYUV400 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
@@ -423,11 +426,11 @@
 void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) {
   asm volatile(
       "vmov.u8     d23, #255                     \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d20}, [%0]!                  \n"
+      "subs        %2, %2, #8                    \n"
       "vmov        d21, d20                      \n"
       "vmov        d22, d20                      \n"
-      "subs        %2, %2, #8                    \n"
       "vst4.8      {d20, d21, d22, d23}, [%1]!   \n"
       "bgt         1b                            \n"
       : "+r"(src_y),     // %0
@@ -445,7 +448,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READNV12 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
@@ -466,7 +470,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READNV21 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READNV21 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
@@ -487,7 +492,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READNV12 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst3.8      {d0, d2, d4}, [%[dst_rgb24]]! \n"
       "bgt         1b                            \n"
@@ -508,7 +514,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READNV21 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READNV21 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst3.8      {d0, d2, d4}, [%[dst_rgb24]]! \n"
       "bgt         1b                            \n"
@@ -529,7 +536,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READNV12 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n" ARGBTORGB565
       "vst1.8      {q2}, [%[dst_rgb565]]!        \n"  // store 8 pixels RGB565.
       "bgt         1b                            \n"
@@ -549,7 +557,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READYUY2 YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READYUY2 YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
@@ -568,7 +577,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "vmov.u8     d6, #255                      \n"
-      "1:                                        \n" READUYVY YUVTORGB RGBTORGB8
+      "1:          \n"  //
+      READUYVY YUVTORGB RGBTORGB8
       "subs        %[width], %[width], #8        \n"
       "vst4.8      {d0, d2, d4, d6}, [%[dst_argb]]! \n"
       "bgt         1b                            \n"
@@ -586,7 +596,7 @@
                      uint8_t* dst_v,
                      int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {q0, q1}, [%0]!               \n"  // load 16 pairs of UV
       "subs        %3, %3, #16                   \n"  // 16 processed per loop
       "vst1.8      {q0}, [%1]!                   \n"  // store U
@@ -610,7 +620,7 @@
                     uint8_t* dst,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0], %3                \n"  // load 16 bytes
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
       "pld         [%0, #1792]                   \n"
@@ -630,7 +640,7 @@
                        uint16_t* dst,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0, q1}, [%0], %3            \n"  // load 16 pixels
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
       "pld         [%0, #3584]                   \n"
@@ -651,7 +661,7 @@
                            uint8_t* dst_v,
                            int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d1}, [%0], %4            \n"
       "subs        %3, %3, #16                   \n"
       "pld         [%0, #1792]                   \n"
@@ -667,7 +677,7 @@
   );
 }
 
-#if LIBYUV_USE_ST2
+#if defined(LIBYUV_USE_ST2)
 // Read 16 Y, 8 UV, and write 8 YUYV.
 void DetileToYUY2_NEON(const uint8_t* src_y,
                        ptrdiff_t src_y_tile_stride,
@@ -676,7 +686,7 @@
                        uint8_t* dst_yuy2,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0], %4                \n"  // Load 16 Y
       "pld         [%0, #1792]                   \n"
       "vld1.8      {q1}, [%1], %5                \n"  // Load 8 UV
@@ -702,7 +712,7 @@
                        uint8_t* dst_yuy2,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0], %4                \n"  // Load 16 Y
       "vld1.8      {q1}, [%1], %5                \n"  // Load 8 UV
       "subs        %3, %3, #16                   \n"
@@ -724,13 +734,14 @@
 
 void UnpackMT2T_NEON(const uint8_t* src, uint16_t* dst, size_t size) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q14}, [%0]!                  \n"  // Load lower bits.
       "vld1.8      {q9}, [%0]!                   \n"  // Load upper bits row
                                                       // by row.
       "vld1.8      {q11}, [%0]!                  \n"
       "vld1.8      {q13}, [%0]!                  \n"
       "vld1.8      {q15}, [%0]!                  \n"
+      "subs        %2, %2, #80                   \n"
       "vshl.u8     q8, q14, #6                   \n"  // Shift lower bit data
                                                       // appropriately.
       "vshl.u8     q10, q14, #4                  \n"
@@ -753,7 +764,6 @@
       "vsri.u16    q15, q15, #10                 \n"
       "vstmia      %1!, {q8-q15}                 \n"  // Store pixel block (64
                                                       // pixels).
-      "subs        %2, %2, #80                   \n"
       "bgt         1b                            \n"
       : "+r"(src),  // %0
         "+r"(dst),  // %1
@@ -768,7 +778,7 @@
                      uint8_t* dst_uv,
                      int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load U
       "vld1.8      {q1}, [%1]!                   \n"  // load V
       "subs        %3, %3, #16                   \n"  // 16 processed per loop
@@ -790,7 +800,7 @@
                       uint8_t* dst_b,
                       int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d0, d2, d4}, [%0]!           \n"  // load 8 RGB
       "vld3.8      {d1, d3, d5}, [%0]!           \n"  // next 8 RGB
       "subs        %4, %4, #16                   \n"  // 16 processed per loop
@@ -815,7 +825,7 @@
                       uint8_t* dst_rgb,
                       int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load R
       "vld1.8      {q1}, [%1]!                   \n"  // load G
       "vld1.8      {q2}, [%2]!                   \n"  // load B
@@ -841,7 +851,7 @@
                        uint8_t* dst_a,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // next 8 ARGB
       "subs        %5, %5, #16                   \n"  // 16 processed per loop
@@ -869,7 +879,7 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q2}, [%0]!                   \n"  // load R
       "vld1.8      {q1}, [%1]!                   \n"  // load G
       "vld1.8      {q0}, [%2]!                   \n"  // load B
@@ -896,7 +906,7 @@
                        uint8_t* dst_b,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // next 8 ARGB
       "subs        %4, %4, #16                   \n"  // 16 processed per loop
@@ -922,7 +932,7 @@
                        int width) {
   asm volatile(
       "vmov.u8     q3, #255                      \n"  // load A(255)
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q2}, [%0]!                   \n"  // load R
       "vld1.8      {q1}, [%1]!                   \n"  // load G
       "vld1.8      {q0}, [%2]!                   \n"  // load B
@@ -950,10 +960,11 @@
   asm volatile(
       "vmov.u32    q14, #1023                    \n"
       "vdup.32     q15, %5                       \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {d4}, [%2]!                   \n"  // B
       "vld1.16     {d2}, [%1]!                   \n"  // G
       "vld1.16     {d0}, [%0]!                   \n"  // R
+      "subs        %4, %4, #4                    \n"
       "vmovl.u16   q2, d4                        \n"  // B
       "vmovl.u16   q1, d2                        \n"  // G
       "vmovl.u16   q0, d0                        \n"  // R
@@ -966,7 +977,6 @@
       "vsli.u32    q2, q1, #10                   \n"  // 00GB
       "vsli.u32    q2, q0, #20                   \n"  // 0RGB
       "vorr.u32    q2, #0xc0000000               \n"  // ARGB (AR30)
-      "subs        %4, %4, #4                    \n"
       "vst1.8      {q2}, [%3]!                   \n"
       "bgt         1b                            \n"
       : "+r"(src_r),     // %0
@@ -986,10 +996,11 @@
                           int width) {
   asm volatile(
       "vmov.u32    q14, #1023                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {d4}, [%2]!                   \n"  // B
       "vld1.16     {d2}, [%1]!                   \n"  // G
       "vld1.16     {d0}, [%0]!                   \n"  // R
+      "subs        %4, %4, #4                    \n"
       "vmovl.u16   q2, d4                        \n"  // 000B
       "vmovl.u16   q1, d2                        \n"  // G
       "vmovl.u16   q0, d0                        \n"  // R
@@ -999,10 +1010,9 @@
       "vsli.u32    q2, q1, #10                   \n"  // 00GB
       "vsli.u32    q2, q0, #20                   \n"  // 0RGB
       "vorr.u32    q2, #0xc0000000               \n"  // ARGB (AR30)
-      "subs        %4, %4, #4                    \n"
       "vst1.8      {q2}, [%3]!                   \n"
       "bgt         1b                            \n"
-      "3:                                        \n"
+      "3:          \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
@@ -1025,11 +1035,12 @@
 
       "vdup.u16    q15, %6                       \n"
       "vdup.u16    q14, %7                       \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q2}, [%0]!                   \n"  // R
       "vld1.16     {q1}, [%1]!                   \n"  // G
       "vld1.16     {q0}, [%2]!                   \n"  // B
       "vld1.16     {q3}, [%3]!                   \n"  // A
+      "subs        %5, %5, #8                    \n"
       "vmin.u16    q2, q2, q14                   \n"
       "vmin.u16    q1, q1, q14                   \n"
       "vmin.u16    q0, q0, q14                   \n"
@@ -1038,7 +1049,6 @@
       "vshl.u16    q1, q1, q15                   \n"
       "vshl.u16    q0, q0, q15                   \n"
       "vshl.u16    q3, q3, q15                   \n"
-      "subs        %5, %5, #8                    \n"
       "vst4.16     {d0, d2, d4, d6}, [%4]!       \n"
       "vst4.16     {d1, d3, d5, d7}, [%4]!       \n"
       "bgt         1b                            \n"
@@ -1066,17 +1076,17 @@
       "vmov.u8     q3, #0xff                     \n"  // A (0xffff)
       "vdup.u16    q15, %5                       \n"
       "vdup.u16    q14, %6                       \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q2}, [%0]!                   \n"  // R
       "vld1.16     {q1}, [%1]!                   \n"  // G
       "vld1.16     {q0}, [%2]!                   \n"  // B
+      "subs        %4, %4, #8                    \n"
       "vmin.u16    q2, q2, q14                   \n"
       "vmin.u16    q1, q1, q14                   \n"
       "vmin.u16    q0, q0, q14                   \n"
       "vshl.u16    q2, q2, q15                   \n"
       "vshl.u16    q1, q1, q15                   \n"
       "vshl.u16    q0, q0, q15                   \n"
-      "subs        %4, %4, #8                    \n"
       "vst4.16     {d0, d2, d4, d6}, [%3]!       \n"
       "vst4.16     {d1, d3, d5, d7}, [%3]!       \n"
       "bgt         1b                            \n"
@@ -1101,11 +1111,12 @@
   asm volatile(
 
       "vdup.16     q15, %6                       \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q2}, [%0]!                   \n"  // R
       "vld1.16     {q1}, [%1]!                   \n"  // G
       "vld1.16     {q0}, [%2]!                   \n"  // B
       "vld1.16     {q3}, [%3]!                   \n"  // A
+      "subs        %5, %5, #8                    \n"
       "vshl.u16    q2, q2, q15                   \n"
       "vshl.u16    q1, q1, q15                   \n"
       "vshl.u16    q0, q0, q15                   \n"
@@ -1114,7 +1125,6 @@
       "vqmovn.u16  d1, q1                        \n"
       "vqmovn.u16  d2, q2                        \n"
       "vqmovn.u16  d3, q3                        \n"
-      "subs        %5, %5, #8                    \n"
       "vst4.8      {d0, d1, d2, d3}, [%4]!       \n"
       "bgt         1b                            \n"
       : "+r"(src_r),     // %0
@@ -1138,17 +1148,17 @@
 
       "vdup.16     q15, %5                       \n"
       "vmov.u8     d6, #0xff                     \n"  // A (0xff)
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q2}, [%0]!                   \n"  // R
       "vld1.16     {q1}, [%1]!                   \n"  // G
       "vld1.16     {q0}, [%2]!                   \n"  // B
+      "subs        %4, %4, #8                    \n"
       "vshl.u16    q2, q2, q15                   \n"
       "vshl.u16    q1, q1, q15                   \n"
       "vshl.u16    q0, q0, q15                   \n"
       "vqmovn.u16  d5, q2                        \n"
       "vqmovn.u16  d4, q1                        \n"
       "vqmovn.u16  d3, q0                        \n"
-      "subs        %4, %4, #8                    \n"
       "vst4.u8     {d3, d4, d5, d6}, [%3]!       \n"
       "bgt         1b                            \n"
       : "+r"(src_r),     // %0
@@ -1163,7 +1173,7 @@
 // Copy multiple of 32.  vld4.8  allow unaligned and is fastest on a15.
 void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 32
       "subs        %2, %2, #32                   \n"  // 32 processed per loop
       "vst1.8      {d0, d1, d2, d3}, [%1]!       \n"  // store 32
@@ -1180,7 +1190,7 @@
 void SetRow_NEON(uint8_t* dst, uint8_t v8, int width) {
   asm volatile(
       "vdup.8      q0, %2                        \n"  // duplicate 16 bytes
-      "1:                                        \n"
+      "1:          \n"
       "subs        %1, %1, #16                   \n"  // 16 bytes per loop
       "vst1.8      {q0}, [%0]!                   \n"  // store
       "bgt         1b                            \n"
@@ -1194,7 +1204,7 @@
 void ARGBSetRow_NEON(uint8_t* dst, uint32_t v32, int width) {
   asm volatile(
       "vdup.u32    q0, %2                        \n"  // duplicate 4 ints
-      "1:                                        \n"
+      "1:          \n"
       "subs        %1, %1, #4                    \n"  // 4 pixels per loop
       "vst1.8      {q0}, [%0]!                   \n"  // store
       "bgt         1b                            \n"
@@ -1210,7 +1220,7 @@
       "add         %0, %0, %2                    \n"
       "sub         %0, %0, #32                   \n"  // 32 bytes per loop
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q1, q2}, [%0], %3            \n"  // src -= 32
       "subs        %2, #32                       \n"  // 32 pixels per loop.
       "vrev64.8    q0, q2                        \n"
@@ -1233,7 +1243,7 @@
       "add         %0, %0, %2, lsl #1            \n"
       "sub         %0, #16                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d1}, [%0], r12           \n"  // src -= 16
       "subs        %2, #8                        \n"  // 8 pixels per loop.
       "vrev64.8    q0, q0                        \n"
@@ -1256,7 +1266,7 @@
       "add         %0, %0, %3, lsl #1            \n"
       "sub         %0, #16                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d1}, [%0], r12           \n"  // src -= 16
       "subs        %3, #8                        \n"  // 8 pixels per loop.
       "vrev64.8    q0, q0                        \n"
@@ -1276,7 +1286,7 @@
       "add         %0, %0, %2, lsl #2            \n"
       "sub         %0, #32                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0], %3    \n"  // src -= 32
       "subs        %2, #8                        \n"  // 8 pixels per loop.
       "vrev64.8    d0, d0                        \n"
@@ -1297,7 +1307,7 @@
                          int width) {
   src_rgb24 += width * 3 - 24;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d0, d1, d2}, [%0], %3        \n"  // src -= 24
       "subs        %2, #8                        \n"  // 8 pixels per loop.
       "vrev64.8    d0, d0                        \n"
@@ -1317,7 +1327,7 @@
                          int width) {
   asm volatile(
       "vmov.u8     d4, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d1, d2, d3}, [%0]!           \n"  // load 8 pixels of RGB24.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vst4.8      {d1, d2, d3, d4}, [%1]!       \n"  // store 8 pixels of ARGB.
@@ -1333,7 +1343,7 @@
 void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
   asm volatile(
       "vmov.u8     d4, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d1, d2, d3}, [%0]!           \n"  // load 8 pixels of RAW.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vswp.u8     d1, d3                        \n"  // swap R, B
@@ -1350,7 +1360,7 @@
 void RAWToRGBARow_NEON(const uint8_t* src_raw, uint8_t* dst_rgba, int width) {
   asm volatile(
       "vmov.u8     d0, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d1, d2, d3}, [%0]!           \n"  // load 8 pixels of RAW.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vswp.u8     d1, d3                        \n"  // swap R, B
@@ -1365,7 +1375,7 @@
 }
 void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d1, d2, d3}, [%0]!           \n"  // load 8 pixels of RAW.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vswp.u8     d1, d3                        \n"  // swap R, B
@@ -1397,7 +1407,7 @@
                           int width) {
   asm volatile(
       "vmov.u8     d3, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 RGB565 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       RGB565TOARGB
@@ -1443,7 +1453,7 @@
                             int width) {
   asm volatile(
       "vmov.u8     d3, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB1555 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGB1555TOARGB
@@ -1472,7 +1482,7 @@
                             int width) {
   asm volatile(
       "vmov.u8     d3, #255                      \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB4444 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGB4444TOARGB
@@ -1490,7 +1500,7 @@
                          uint8_t* dst_rgb24,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 16 pixels of ARGB.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"
       "subs        %2, %2, #16                   \n"  // 16 processed per loop.
@@ -1507,7 +1517,7 @@
 
 void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d1, d2, d3, d4}, [%0]!       \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vswp.u8     d1, d3                        \n"  // swap R, B
@@ -1523,7 +1533,7 @@
 
 void YUY2ToYRow_NEON(const uint8_t* src_yuy2, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {q0, q1}, [%0]!               \n"  // load 16 pixels of YUY2.
       "subs        %2, %2, #16                   \n"  // 16 processed per loop.
       "vst1.8      {q0}, [%1]!                   \n"  // store 16 pixels of Y.
@@ -1538,7 +1548,7 @@
 
 void UYVYToYRow_NEON(const uint8_t* src_uyvy, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {q0, q1}, [%0]!               \n"  // load 16 pixels of UYVY.
       "subs        %2, %2, #16                   \n"  // 16 processed per loop.
       "vst1.8      {q1}, [%1]!                   \n"  // store 16 pixels of Y.
@@ -1556,7 +1566,7 @@
                          uint8_t* dst_v,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 16 pixels of YUY2.
       "subs        %3, %3, #16                   \n"  // 16 pixels = 8 UVs.
       "vst1.8      {d1}, [%1]!                   \n"  // store 8 U.
@@ -1576,7 +1586,7 @@
                          uint8_t* dst_v,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 16 pixels of UYVY.
       "subs        %3, %3, #16                   \n"  // 16 pixels = 8 UVs.
       "vst1.8      {d0}, [%1]!                   \n"  // store 8 U.
@@ -1598,10 +1608,10 @@
                       int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // stride + src_yuy2
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 16 pixels of YUY2.
-      "subs        %4, %4, #16                   \n"  // 16 pixels = 8 UVs.
       "vld4.8      {d4, d5, d6, d7}, [%1]!       \n"  // load next row YUY2.
+      "subs        %4, %4, #16                   \n"  // 16 pixels = 8 UVs.
       "vrhadd.u8   d1, d1, d5                    \n"  // average rows of U
       "vrhadd.u8   d3, d3, d7                    \n"  // average rows of V
       "vst1.8      {d1}, [%2]!                   \n"  // store 8 U.
@@ -1625,10 +1635,10 @@
                       int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // stride + src_uyvy
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 16 pixels of UYVY.
-      "subs        %4, %4, #16                   \n"  // 16 pixels = 8 UVs.
       "vld4.8      {d4, d5, d6, d7}, [%1]!       \n"  // load next row UYVY.
+      "subs        %4, %4, #16                   \n"  // 16 pixels = 8 UVs.
       "vrhadd.u8   d0, d0, d4                    \n"  // average rows of U
       "vrhadd.u8   d2, d2, d6                    \n"  // average rows of V
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 U.
@@ -1651,7 +1661,7 @@
                         int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // stride + src_yuy2
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {q0, q1}, [%0]!               \n"  // load 16 pixels of YUY2.
       "subs        %3, %3, #16                   \n"  // 16 pixels = 8 UVs.
       "vld2.8      {q2, q3}, [%1]!               \n"  // load next row YUY2.
@@ -1675,7 +1685,7 @@
                          int width) {
   asm volatile(
       "vld1.8      {q2}, [%3]                    \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 4 pixels.
       "subs        %2, %2, #4                    \n"  // 4 processed per loop
       "vtbl.8      d2, {d0, d1}, d4              \n"  // look up 2 first pixels
@@ -1696,7 +1706,7 @@
                         uint8_t* dst_yuy2,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d2}, [%0]!               \n"  // load 16 Ys
       "vld1.8      {d1}, [%1]!                   \n"  // load 8 Us
       "vld1.8      {d3}, [%2]!                   \n"  // load 8 Vs
@@ -1718,7 +1728,7 @@
                         uint8_t* dst_uyvy,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d1, d3}, [%0]!               \n"  // load 16 Ys
       "vld1.8      {d0}, [%1]!                   \n"  // load 8 Us
       "vld1.8      {d2}, [%2]!                   \n"  // load 8 Vs
@@ -1738,7 +1748,7 @@
                           uint8_t* dst_rgb565,
                           int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGBTORGB565
@@ -1757,7 +1767,7 @@
                                 int width) {
   asm volatile(
       "vdup.32     d7, %2                        \n"  // dither4
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%1]!       \n"  // load 8 pixels of ARGB.
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
       "vqadd.u8    d0, d0, d7                    \n"
@@ -1777,7 +1787,7 @@
                             uint8_t* dst_argb1555,
                             int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGBTOARGB1555
@@ -1796,7 +1806,7 @@
   asm volatile(
       "vmov.u8     d7, #0x0f                     \n"  // bits to clear with
                                                       // vbic.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGBTOARGB4444
@@ -1813,7 +1823,7 @@
                               uint8_t* dst_a,
                               int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB pixels
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
@@ -1827,28 +1837,30 @@
   );
 }
 
+// Coefficients expressed as negatives to allow 128
 struct RgbUVConstants {
-  uint8_t kRGBToU[4];
-  uint8_t kRGBToV[4];
+  int8_t kRGBToU[4];
+  int8_t kRGBToV[4];
 };
 
 // 8x1 pixels.
-void ARGBToUV444MatrixRow_NEON(const uint8_t* src_argb,
-                               uint8_t* dst_u,
-                               uint8_t* dst_v,
-                               int width,
-                               const struct RgbUVConstants* rgbuvconstants) {
+static void ARGBToUV444MatrixRow_NEON(
+    const uint8_t* src_argb,
+    uint8_t* dst_u,
+    uint8_t* dst_v,
+    int width,
+    const struct RgbUVConstants* rgbuvconstants) {
   asm volatile(
-
       "vld1.8      {d0}, [%4]                    \n"  // load rgbuvconstants
       "vdup.u8     d24, d0[0]                    \n"  // UB  0.875  coefficient
       "vdup.u8     d25, d0[1]                    \n"  // UG -0.5781 coefficient
       "vdup.u8     d26, d0[2]                    \n"  // UR -0.2969 coefficient
       "vdup.u8     d27, d0[4]                    \n"  // VB -0.1406 coefficient
       "vdup.u8     d28, d0[5]                    \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
+      "vneg.s8     d24, d24                      \n"
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
 
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 ARGB pixels.
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
       "vmull.u8    q2, d0, d24                   \n"  // B
@@ -1859,8 +1871,8 @@
       "vmlsl.u8    q3, d1, d28                   \n"  // G
       "vmlsl.u8    q3, d0, d27                   \n"  // B
 
-      "vaddhn.u16  d0, q2, q15                   \n"  // +128 -> unsigned
-      "vaddhn.u16  d1, q3, q15                   \n"  // +128 -> unsigned
+      "vaddhn.u16  d0, q2, q15                   \n"  // signed -> unsigned
+      "vaddhn.u16  d1, q3, q15                   \n"
 
       "vst1.8      {d0}, [%1]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%2]!                   \n"  // store 8 pixels V.
@@ -1874,42 +1886,42 @@
         "q15");
 }
 
-// RGB to bt601 coefficients
+// RGB to BT601 coefficients
 // UB   0.875 coefficient = 112
-// UG -0.5781 coefficient = 74
-// UR -0.2969 coefficient = 38
-// VB -0.1406 coefficient = 18
-// VG -0.7344 coefficient = 94
-// VR   0.875 coefficient = 112 (ignored)
+// UG -0.5781 coefficient = -74
+// UR -0.2969 coefficient = -38
+// VB -0.1406 coefficient = -18
+// VG -0.7344 coefficient = -94
+// VR   0.875 coefficient = 112
 
-static const struct RgbUVConstants kRgb24I601UVConstants = {{112, 74, 38, 0},
-                                                            {18, 94, 112, 0}};
-
-// RGB to JPeg coefficients
-// UB coeff 0.500    = 127
-// UG coeff -0.33126 = 84
-// UR coeff -0.16874 = 43
-// VB coeff -0.08131 = 20
-// VG coeff -0.41869 = 107
-// VR coeff 0.500    = 127 (ignored)
-
-static const struct RgbUVConstants kRgb24JPegUVConstants = {{127, 84, 43, 0},
-                                                            {20, 107, 127, 0}};
+static const struct RgbUVConstants kARGBI601UVConstants = {{-112, 74, 38, 0},
+                                                           {18, 94, -112, 0}};
 
 void ARGBToUV444Row_NEON(const uint8_t* src_argb,
                          uint8_t* dst_u,
                          uint8_t* dst_v,
                          int width) {
   ARGBToUV444MatrixRow_NEON(src_argb, dst_u, dst_v, width,
-                            &kRgb24I601UVConstants);
+                            &kARGBI601UVConstants);
 }
 
+// RGB to JPEG coefficients
+// UB  0.500    coefficient = 128
+// UG -0.33126  coefficient = -85
+// UR -0.16874  coefficient = -43
+// VB -0.08131  coefficient = -21
+// VG -0.41869  coefficient = -107
+// VR 0.500     coefficient = 128
+
+static const struct RgbUVConstants kARGBJPEGUVConstants = {{-128, 85, 43, 0},
+                                                           {21, 107, -128, 0}};
+
 void ARGBToUVJ444Row_NEON(const uint8_t* src_argb,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width) {
   ARGBToUV444MatrixRow_NEON(src_argb, dst_u, dst_v, width,
-                            &kRgb24JPegUVConstants);
+                            &kARGBJPEGUVConstants);
 }
 
 // clang-format off
@@ -1933,15 +1945,16 @@
                       int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // R 16 bytes -> 8 shorts.
@@ -1951,11 +1964,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -1971,7 +1983,6 @@
   );
 }
 
-// TODO(fbarchard): Subsample match Intel code.
 void ARGBToUVJRow_NEON(const uint8_t* src_argb,
                        int src_stride_argb,
                        uint8_t* dst_u,
@@ -1979,15 +1990,16 @@
                        int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #127 / 2                 \n"  // UB / VR 0.500 coefficient
-      "vmov.s16    q11, #84 / 2                  \n"  // UG -0.33126 coefficient
-      "vmov.s16    q12, #43 / 2                  \n"  // UR -0.16874 coefficient
-      "vmov.s16    q13, #20 / 2                  \n"  // VB -0.08131 coefficient
-      "vmov.s16    q14, #107 / 2                 \n"  // VG -0.41869 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #128                     \n"  // UB/VR 0.500 coefficient
+      "vmov.s16    q11, #85                      \n"  // UG -0.33126 coefficient
+      "vmov.s16    q12, #43                      \n"  // UR -0.16874 coefficient
+      "vmov.s16    q13, #21                      \n"  // VB -0.08131 coefficient
+      "vmov.s16    q14, #107                     \n"  // VG -0.41869 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // R 16 bytes -> 8 shorts.
@@ -1997,11 +2009,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2024,15 +2035,16 @@
                        int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #127 / 2                 \n"  // UB / VR 0.500 coefficient
-      "vmov.s16    q11, #84 / 2                  \n"  // UG -0.33126 coefficient
-      "vmov.s16    q12, #43 / 2                  \n"  // UR -0.16874 coefficient
-      "vmov.s16    q13, #20 / 2                  \n"  // VB -0.08131 coefficient
-      "vmov.s16    q14, #107 / 2                 \n"  // VG -0.41869 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #128                     \n"  // UB/VR 0.500 coefficient
+      "vmov.s16    q11, #85                      \n"  // UG -0.33126 coefficient
+      "vmov.s16    q12, #43                      \n"  // UR -0.16874 coefficient
+      "vmov.s16    q13, #21                      \n"  // VB -0.08131 coefficient
+      "vmov.s16    q14, #107                     \n"  // VG -0.41869 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ABGR pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ABGR pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // R 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // B 16 bytes -> 8 shorts.
@@ -2042,11 +2054,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // B 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q2, q1, q0)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2062,7 +2073,6 @@
   );
 }
 
-// TODO(fbarchard): Subsample match C code.
 void RGB24ToUVJRow_NEON(const uint8_t* src_rgb24,
                         int src_stride_rgb24,
                         uint8_t* dst_u,
@@ -2070,15 +2080,16 @@
                         int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_rgb24
-      "vmov.s16    q10, #127 / 2                 \n"  // UB / VR 0.500 coefficient
-      "vmov.s16    q11, #84 / 2                  \n"  // UG -0.33126 coefficient
-      "vmov.s16    q12, #43 / 2                  \n"  // UR -0.16874 coefficient
-      "vmov.s16    q13, #20 / 2                  \n"  // VB -0.08131 coefficient
-      "vmov.s16    q14, #107 / 2                 \n"  // VG -0.41869 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #128                     \n"  // UB/VR 0.500 coefficient
+      "vmov.s16    q11, #85                      \n"  // UG -0.33126 coefficient
+      "vmov.s16    q12, #43                      \n"  // UR -0.16874 coefficient
+      "vmov.s16    q13, #21                      \n"  // VB -0.08131 coefficient
+      "vmov.s16    q14, #107                     \n"  // VG -0.41869 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld3.8      {d0, d2, d4}, [%0]!           \n"  // load 8 RGB24 pixels.
       "vld3.8      {d1, d3, d5}, [%0]!           \n"  // load next 8 RGB24 pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // R 16 bytes -> 8 shorts.
@@ -2088,11 +2099,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2108,7 +2118,6 @@
   );
 }
 
-// TODO(fbarchard): Subsample match C code.
 void RAWToUVJRow_NEON(const uint8_t* src_raw,
                       int src_stride_raw,
                       uint8_t* dst_u,
@@ -2116,15 +2125,16 @@
                       int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_raw
-      "vmov.s16    q10, #127 / 2                 \n"  // UB / VR 0.500 coefficient
-      "vmov.s16    q11, #84 / 2                  \n"  // UG -0.33126 coefficient
-      "vmov.s16    q12, #43 / 2                  \n"  // UR -0.16874 coefficient
-      "vmov.s16    q13, #20 / 2                  \n"  // VB -0.08131 coefficient
-      "vmov.s16    q14, #107 / 2                 \n"  // VG -0.41869 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #128                     \n"  // UB/VR 0.500 coefficient
+      "vmov.s16    q11, #85                      \n"  // UG -0.33126 coefficient
+      "vmov.s16    q12, #43                      \n"  // UR -0.16874 coefficient
+      "vmov.s16    q13, #21                      \n"  // VB -0.08131 coefficient
+      "vmov.s16    q14, #107                     \n"  // VG -0.41869 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld3.8      {d0, d2, d4}, [%0]!           \n"  // load 8 RAW pixels.
       "vld3.8      {d1, d3, d5}, [%0]!           \n"  // load next 8 RAW pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // R 16 bytes -> 8 shorts.
@@ -2134,11 +2144,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q2, q1, q0)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2161,15 +2170,16 @@
                       int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_bgra
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 BGRA pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 BGRA pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q3, q3                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // R 16 bytes -> 8 shorts.
@@ -2179,18 +2189,17 @@
       "vpadal.u8   q2, q6                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q1, q5                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q1, q1, #1                    \n"  // 2x average
-      "vrshr.u16   q2, q2, #1                    \n"
-      "vrshr.u16   q3, q3, #1                    \n"
+      "vrshr.u16   q1, q1, #2                    \n"  // average of 4
+      "vrshr.u16   q2, q2, #2                    \n"
+      "vrshr.u16   q3, q3, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q3, q2, q1)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
       "bgt         1b                            \n"
   : "+r"(src_bgra),  // %0
     "+r"(src_stride_bgra),  // %1
-    "+r"(dst_u),     // %2
+    "+r"(dst_u),     // %2-
     "+r"(dst_v),     // %3
     "+r"(width)        // %4
   :
@@ -2206,15 +2215,16 @@
                       int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_abgr
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ABGR pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ABGR pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q2, q2                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q0, q0                        \n"  // R 16 bytes -> 8 shorts.
@@ -2224,11 +2234,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q0, q4                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q2, q1, q0)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2251,15 +2260,16 @@
                       int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_rgba
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 RGBA pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 RGBA pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q1                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q2                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q3                        \n"  // R 16 bytes -> 8 shorts.
@@ -2269,11 +2279,10 @@
       "vpadal.u8   q1, q6                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q7                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2296,15 +2305,16 @@
                        int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_rgb24
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld3.8      {d0, d2, d4}, [%0]!           \n"  // load 8 RGB24 pixels.
       "vld3.8      {d1, d3, d5}, [%0]!           \n"  // load next 8 RGB24 pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q2, q2                        \n"  // R 16 bytes -> 8 shorts.
@@ -2314,11 +2324,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q2, q6                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2341,15 +2350,16 @@
                      int width) {
   asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_raw
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875 coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld3.8      {d0, d2, d4}, [%0]!           \n"  // load 8 RAW pixels.
       "vld3.8      {d1, d3, d5}, [%0]!           \n"  // load next 8 RAW pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q2, q2                        \n"  // B 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // G 16 bytes -> 8 shorts.
       "vpaddl.u8   q0, q0                        \n"  // R 16 bytes -> 8 shorts.
@@ -2359,11 +2369,10 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vpadal.u8   q0, q4                        \n"  // R 16 bytes -> 8 shorts.
 
-      "vrshr.u16   q0, q0, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q1, #1                    \n"
-      "vrshr.u16   q2, q2, #1                    \n"
+      "vrshr.u16   q0, q0, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q1, #2                    \n"
+      "vrshr.u16   q2, q2, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
     RGBTOUV(q2, q1, q0)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2387,15 +2396,15 @@
                         int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875
-                                                      // coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 RGB565 pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       RGB565TOARGB
       "vpaddl.u8   d8, d0                        \n"  // B 8 bytes -> 4 shorts.
       "vpaddl.u8   d10, d1                       \n"  // G 8 bytes -> 4 shorts.
@@ -2417,11 +2426,10 @@
       "vpadal.u8   d11, d1                       \n"  // G 8 bytes -> 4 shorts.
       "vpadal.u8   d13, d2                       \n"  // R 8 bytes -> 4 shorts.
 
-      "vrshr.u16   q4, q4, #1                    \n"  // 2x average
-      "vrshr.u16   q5, q5, #1                    \n"
-      "vrshr.u16   q6, q6, #1                    \n"
+      "vrshr.u16   q4, q4, #2                    \n"  // average of 4
+      "vrshr.u16   q5, q5, #2                    \n"
+      "vrshr.u16   q6, q6, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vmul.s16    q8, q4, q10                   \n"  // B
       "vmls.s16    q8, q5, q11                   \n"  // G
       "vmls.s16    q8, q6, q12                   \n"  // R
@@ -2453,15 +2461,15 @@
                           int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875
-                                                      // coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB1555 pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       RGB555TOARGB
       "vpaddl.u8   d8, d0                        \n"  // B 8 bytes -> 4 shorts.
       "vpaddl.u8   d10, d1                       \n"  // G 8 bytes -> 4 shorts.
@@ -2483,11 +2491,10 @@
       "vpadal.u8   d11, d1                       \n"  // G 8 bytes -> 4 shorts.
       "vpadal.u8   d13, d2                       \n"  // R 8 bytes -> 4 shorts.
 
-      "vrshr.u16   q4, q4, #1                    \n"  // 2x average
-      "vrshr.u16   q5, q5, #1                    \n"
-      "vrshr.u16   q6, q6, #1                    \n"
+      "vrshr.u16   q4, q4, #2                    \n"  // average of 4
+      "vrshr.u16   q5, q5, #2                    \n"
+      "vrshr.u16   q6, q6, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       "vmul.s16    q8, q4, q10                   \n"  // B
       "vmls.s16    q8, q5, q11                   \n"  // G
       "vmls.s16    q8, q6, q12                   \n"  // R
@@ -2517,17 +2524,17 @@
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width) {
-  asm volatile(
+  asm volatile (
       "add         %1, %0, %1                    \n"  // src_stride + src_argb
-      "vmov.s16    q10, #112 / 2                 \n"  // UB / VR 0.875
-                                                      // coefficient
-      "vmov.s16    q11, #74 / 2                  \n"  // UG -0.5781 coefficient
-      "vmov.s16    q12, #38 / 2                  \n"  // UR -0.2969 coefficient
-      "vmov.s16    q13, #18 / 2                  \n"  // VB -0.1406 coefficient
-      "vmov.s16    q14, #94 / 2                  \n"  // VG -0.7344 coefficient
-      "vmov.u16    q15, #0x8080                  \n"  // 128.5
-      "1:                                        \n"
+      "vmov.s16    q10, #112                     \n"  // UB/VR 0.875 coefficient
+      "vmov.s16    q11, #74                      \n"  // UG -0.5781 coefficient
+      "vmov.s16    q12, #38                      \n"  // UR -0.2969 coefficient
+      "vmov.s16    q13, #18                      \n"  // VB -0.1406 coefficient
+      "vmov.s16    q14, #94                      \n"  // VG -0.7344 coefficient
+      "vmov.u16    q15, #0x8000                  \n"  // 128.0
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB4444 pixels.
+      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       ARGB4444TOARGB
       "vpaddl.u8   d8, d0                        \n"  // B 8 bytes -> 4 shorts.
       "vpaddl.u8   d10, d1                       \n"  // G 8 bytes -> 4 shorts.
@@ -2549,11 +2556,10 @@
       "vpadal.u8   d11, d1                       \n"  // G 8 bytes -> 4 shorts.
       "vpadal.u8   d13, d2                       \n"  // R 8 bytes -> 4 shorts.
 
-      "vrshr.u16   q0, q4, #1                    \n"  // 2x average
-      "vrshr.u16   q1, q5, #1                    \n"
-      "vrshr.u16   q2, q6, #1                    \n"
+      "vrshr.u16   q0, q4, #2                    \n"  // average of 4
+      "vrshr.u16   q1, q5, #2                    \n"
+      "vrshr.u16   q2, q6, #2                    \n"
 
-      "subs        %4, %4, #16                   \n"  // 16 processed per loop.
       RGBTOUV(q0, q1, q2)
       "vst1.8      {d0}, [%2]!                   \n"  // store 8 pixels U.
       "vst1.8      {d1}, [%3]!                   \n"  // store 8 pixels V.
@@ -2574,7 +2580,7 @@
       "vmov.u8     d25, #129                     \n"  // G * 0.5078 coefficient
       "vmov.u8     d26, #66                      \n"  // R * 0.2578 coefficient
       "vmov.u8     d27, #16                      \n"  // Add 16 constant
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 RGB565 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       RGB565TOARGB
@@ -2600,7 +2606,7 @@
       "vmov.u8     d25, #129                     \n"  // G * 0.5078 coefficient
       "vmov.u8     d26, #66                      \n"  // R * 0.2578 coefficient
       "vmov.u8     d27, #16                      \n"  // Add 16 constant
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB1555 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGB1555TOARGB
@@ -2626,7 +2632,7 @@
       "vmov.u8     d25, #129                     \n"  // G * 0.5078 coefficient
       "vmov.u8     d26, #66                      \n"  // R * 0.2578 coefficient
       "vmov.u8     d27, #16                      \n"  // Add 16 constant
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 8 ARGB4444 pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       ARGB4444TOARGB
@@ -2648,12 +2654,12 @@
                         uint16_t* dst_ar64,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"
       "vld1.8      {q2}, [%0]!                   \n"
+      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vmov.u8     q1, q0                        \n"
       "vmov.u8     q3, q2                        \n"
-      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vst2.8      {q0, q1}, [%1]!               \n"  // store 4 pixels
       "vst2.8      {q2, q3}, [%1]!               \n"  // store 4 pixels
       "bgt         1b                            \n"
@@ -2673,16 +2679,16 @@
   asm volatile(
       "vld1.8      {q4}, [%3]                    \n"  // shuffler
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"
       "vld1.8      {q2}, [%0]!                   \n"
+      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vtbl.8      d2, {d0, d1}, d8              \n"
       "vtbl.8      d3, {d0, d1}, d9              \n"
       "vtbl.8      d6, {d4, d5}, d8              \n"
       "vtbl.8      d7, {d4, d5}, d9              \n"
       "vmov.u8     q0, q1                        \n"
       "vmov.u8     q2, q3                        \n"
-      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vst2.8      {q0, q1}, [%1]!               \n"  // store 4 pixels
       "vst2.8      {q2, q3}, [%1]!               \n"  // store 4 pixels
       "bgt         1b                            \n"
@@ -2697,16 +2703,16 @@
                         uint8_t* dst_argb,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"
       "vld1.16     {q1}, [%0]!                   \n"
       "vld1.16     {q2}, [%0]!                   \n"
       "vld1.16     {q3}, [%0]!                   \n"
+      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vshrn.u16   d0, q0, #8                    \n"
       "vshrn.u16   d1, q1, #8                    \n"
       "vshrn.u16   d4, q2, #8                    \n"
       "vshrn.u16   d5, q3, #8                    \n"
-      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vst1.8      {q0}, [%1]!                   \n"  // store 4 pixels
       "vst1.8      {q2}, [%1]!                   \n"  // store 4 pixels
       "bgt         1b                            \n"
@@ -2725,16 +2731,16 @@
   asm volatile(
       "vld1.8      {d8}, [%3]                    \n"  // shuffler
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"
       "vld1.16     {q1}, [%0]!                   \n"
       "vld1.16     {q2}, [%0]!                   \n"
       "vld1.16     {q3}, [%0]!                   \n"
+      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vtbl.8      d0, {d0, d1}, d8              \n"
       "vtbl.8      d1, {d2, d3}, d8              \n"
       "vtbl.8      d4, {d4, d5}, d8              \n"
       "vtbl.8      d5, {d6, d7}, d8              \n"
-      "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vst1.8      {q0}, [%1]!                   \n"  // store 4 pixels
       "vst1.8      {q2}, [%1]!                   \n"  // store 4 pixels
       "bgt         1b                            \n"
@@ -2754,10 +2760,11 @@
 // B * 0.1140 coefficient = 29
 // G * 0.5870 coefficient = 150
 // R * 0.2990 coefficient = 77
-// Add 0.5 = 0x80
-static const struct RgbConstants kRgb24JPEGConstants = {{29, 150, 77, 0}, 128};
+// Add 0.5
+static const struct RgbConstants kRgb24JPEGConstants = {{29, 150, 77, 0},
+                                                        0x0080};
 
-static const struct RgbConstants kRawJPEGConstants = {{77, 150, 29, 0}, 128};
+static const struct RgbConstants kRawJPEGConstants = {{77, 150, 29, 0}, 0x0080};
 
 // RGB to BT.601 coefficients
 // B * 0.1016 coefficient = 25
@@ -2771,17 +2778,17 @@
 static const struct RgbConstants kRawI601Constants = {{66, 129, 25, 0}, 0x1080};
 
 // ARGB expects first 3 values to contain RGB and 4th value is ignored.
-void ARGBToYMatrixRow_NEON(const uint8_t* src_argb,
-                           uint8_t* dst_y,
-                           int width,
-                           const struct RgbConstants* rgbconstants) {
+static void ARGBToYMatrixRow_NEON(const uint8_t* src_argb,
+                                  uint8_t* dst_y,
+                                  int width,
+                                  const struct RgbConstants* rgbconstants) {
   asm volatile(
       "vld1.8      {d0}, [%3]                    \n"  // load rgbconstants
       "vdup.u8     d20, d0[0]                    \n"
       "vdup.u8     d21, d0[1]                    \n"
       "vdup.u8     d22, d0[2]                    \n"
       "vdup.u16    q12, d0[2]                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 16 pixels of ARGB
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"
       "subs        %2, %2, #16                   \n"  // 16 processed per loop.
@@ -2821,17 +2828,17 @@
 
 // RGBA expects first value to be A and ignored, then 3 values to contain RGB.
 // Same code as ARGB, except the LD4
-void RGBAToYMatrixRow_NEON(const uint8_t* src_rgba,
-                           uint8_t* dst_y,
-                           int width,
-                           const struct RgbConstants* rgbconstants) {
+static void RGBAToYMatrixRow_NEON(const uint8_t* src_rgba,
+                                  uint8_t* dst_y,
+                                  int width,
+                                  const struct RgbConstants* rgbconstants) {
   asm volatile(
       "vld1.8      {d0}, [%3]                    \n"  // load rgbconstants
       "vdup.u8     d20, d0[0]                    \n"
       "vdup.u8     d21, d0[1]                    \n"
       "vdup.u8     d22, d0[2]                    \n"
       "vdup.u16    q12, d0[2]                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 16 pixels of RGBA
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"
       "subs        %2, %2, #16                   \n"  // 16 processed per loop.
@@ -2865,17 +2872,17 @@
   RGBAToYMatrixRow_NEON(src_bgra, dst_y, width, &kRawI601Constants);
 }
 
-void RGBToYMatrixRow_NEON(const uint8_t* src_rgb,
-                          uint8_t* dst_y,
-                          int width,
-                          const struct RgbConstants* rgbconstants) {
+static void RGBToYMatrixRow_NEON(const uint8_t* src_rgb,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
   asm volatile(
       "vld1.8      {d0}, [%3]                    \n"  // load rgbconstants
       "vdup.u8     d20, d0[0]                    \n"
       "vdup.u8     d21, d0[1]                    \n"
       "vdup.u8     d22, d0[2]                    \n"
       "vdup.u16    q12, d0[2]                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld3.8      {d2, d4, d6}, [%0]!           \n"  // load 16 pixels of
                                                       // RGB24.
       "vld3.8      {d3, d5, d7}, [%0]!           \n"
@@ -2932,7 +2939,7 @@
       "rsb         %4, #256                      \n"
       "vdup.8      d4, %4                        \n"
       // General purpose row blend.
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%1]!                   \n"
       "vld1.8      {q1}, [%2]!                   \n"
       "subs        %3, %3, #16                   \n"
@@ -2947,7 +2954,7 @@
       "b           99f                           \n"
 
       // Blend 50 / 50.
-      "50:                                       \n"
+      "50:         \n"
       "vld1.8      {q0}, [%1]!                   \n"
       "vld1.8      {q1}, [%2]!                   \n"
       "subs        %3, %3, #16                   \n"
@@ -2957,13 +2964,13 @@
       "b           99f                           \n"
 
       // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
+      "100:        \n"
       "vld1.8      {q0}, [%1]!                   \n"
       "subs        %3, %3, #16                   \n"
       "vst1.8      {q0}, [%0]!                   \n"
       "bgt         100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),     // %0
         "+r"(src_ptr),     // %1
         "+r"(src_stride),  // %2
@@ -2992,7 +2999,7 @@
       "vdup.16     d17, %4                       \n"
       "vdup.16     d16, %5                       \n"
       // General purpose row blend.
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%1]!                   \n"
       "vld1.16     {q1}, [%2]!                   \n"
       "subs        %3, %3, #8                    \n"
@@ -3007,7 +3014,7 @@
       "b           99f                           \n"
 
       // Blend 50 / 50.
-      "50:                                       \n"
+      "50:         \n"
       "vld1.16     {q0}, [%1]!                   \n"
       "vld1.16     {q1}, [%2]!                   \n"
       "subs        %3, %3, #8                    \n"
@@ -3017,13 +3024,13 @@
       "b           99f                           \n"
 
       // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
+      "100:        \n"
       "vld1.16     {q0}, [%1]!                   \n"
       "subs        %3, %3, #8                    \n"
       "vst1.16     {q0}, [%0]!                   \n"
       "bgt         100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),     // %0
         "+r"(src_ptr),     // %1
         "+r"(src_ptr1),    // %2
@@ -3042,7 +3049,7 @@
       "subs        %3, #8                        \n"
       "blt         89f                           \n"
       // Blend 8 pixels.
-      "8:                                        \n"
+      "8:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 pixels of ARGB0.
       "vld4.8      {d4, d5, d6, d7}, [%1]!       \n"  // load 8 pixels of ARGB1.
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3060,12 +3067,12 @@
       "vst4.8      {d0, d1, d2, d3}, [%2]!       \n"  // store 8 pixels of ARGB.
       "bge         8b                            \n"
 
-      "89:                                       \n"
+      "89:         \n"
       "adds        %3, #8-1                      \n"
       "blt         99f                           \n"
 
       // Blend 1 pixels.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n"  // load 1 pixel ARGB0.
       "vld4.8      {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n"  // load 1 pixel ARGB1.
       "subs        %3, %3, #1                    \n"  // 1 processed per loop.
@@ -3083,7 +3090,7 @@
       "vst4.8      {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n"  // store 1 pixel.
       "bge         1b                            \n"
 
-      "99:                                       \n"
+      "99:         \n"
 
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
@@ -3101,7 +3108,7 @@
       "vmov.u16    q15, #0x00ff                  \n"  // 255 for rounding up
 
       // Attenuate 8 pixels.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vmull.u8    q10, d0, d3                   \n"  // b * a
@@ -3133,7 +3140,7 @@
       "vdup.u16    q10, %4                       \n"  // interval add
 
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]        \n"  // load 8 pixels of ARGB.
       "subs        %1, %1, #8                    \n"  // 8 processed per loop.
       "vmovl.u8    q0, d0                        \n"  // b (0 .. 255)
@@ -3174,7 +3181,7 @@
       "vshr.u16    q0, q0, #1                    \n"  // scale / 2.
 
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d20, d22, d24, d26}, [%0]!   \n"  // load 8 pixels of ARGB.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vmovl.u8    q10, d20                      \n"  // b (0 .. 255)
@@ -3206,7 +3213,7 @@
       "vmov.u8     d24, #29                      \n"  // B * 0.1140 coefficient
       "vmov.u8     d25, #150                     \n"  // G * 0.5870 coefficient
       "vmov.u8     d26, #77                      \n"  // R * 0.2990 coefficient
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 ARGB pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vmull.u8    q2, d0, d24                   \n"  // B
@@ -3239,7 +3246,7 @@
       "vmov.u8     d28, #24                      \n"  // BB coefficient
       "vmov.u8     d29, #98                      \n"  // BG coefficient
       "vmov.u8     d30, #50                      \n"  // BR coefficient
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]        \n"  // load 8 ARGB pixels.
       "subs        %1, %1, #8                    \n"  // 8 processed per loop.
       "vmull.u8    q2, d0, d20                   \n"  // B to Sepia B
@@ -3275,7 +3282,7 @@
       "vmovl.s8    q0, d4                        \n"  // B,G coefficients s16.
       "vmovl.s8    q1, d5                        \n"  // R,A coefficients s16.
 
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d16, d18, d20, d22}, [%0]!   \n"  // load 8 ARGB pixels.
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
       "vmovl.u8    q8, d16                       \n"  // b (0 .. 255) 16 bit
@@ -3331,7 +3338,7 @@
                           int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d1, d3, d5, d7}, [%1]!       \n"  // load 8 more ARGB
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3360,7 +3367,7 @@
                      int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d4, d5, d6, d7}, [%1]!       \n"  // load 8 more ARGB
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3383,7 +3390,7 @@
                           int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d4, d5, d6, d7}, [%1]!       \n"  // load 8 more ARGB
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3411,7 +3418,7 @@
   asm volatile(
       "vmov.u8     d3, #255                      \n"  // alpha
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0}, [%0]!                   \n"  // load 8 sobelx.
       "vld1.8      {d1}, [%1]!                   \n"  // load 8 sobely.
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3435,7 +3442,7 @@
                           int width) {
   asm volatile(
       // 16 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 16 sobelx.
       "vld1.8      {q1}, [%1]!                   \n"  // load 16 sobely.
       "subs        %3, %3, #16                   \n"  // 16 processed per loop.
@@ -3462,7 +3469,7 @@
   asm volatile(
       "vmov.u8     d3, #255                      \n"  // alpha
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d2}, [%0]!                   \n"  // load 8 sobelx.
       "vld1.8      {d0}, [%1]!                   \n"  // load 8 sobely.
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -3487,9 +3494,10 @@
                     uint8_t* dst_sobelx,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0}, [%0],%5                 \n"  // top
       "vld1.8      {d1}, [%0],%6                 \n"
+      "subs        %4, %4, #8                    \n"  // 8 pixels
       "vsubl.u8    q0, d0, d1                    \n"
       "vld1.8      {d2}, [%1],%5                 \n"  // center * 2
       "vld1.8      {d3}, [%1],%6                 \n"
@@ -3498,7 +3506,6 @@
       "vadd.s16    q0, q0, q1                    \n"
       "vld1.8      {d2}, [%2],%5                 \n"  // bottom
       "vld1.8      {d3}, [%2],%6                 \n"
-      "subs        %4, %4, #8                    \n"  // 8 pixels
       "vsubl.u8    q1, d2, d3                    \n"
       "vadd.s16    q0, q0, q1                    \n"
       "vabs.s16    q0, q0                        \n"
@@ -3525,9 +3532,10 @@
                     uint8_t* dst_sobely,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0}, [%0],%4                 \n"  // left
       "vld1.8      {d1}, [%1],%4                 \n"
+      "subs        %3, %3, #8                    \n"  // 8 pixels
       "vsubl.u8    q0, d0, d1                    \n"
       "vld1.8      {d2}, [%0],%4                 \n"  // center * 2
       "vld1.8      {d3}, [%1],%4                 \n"
@@ -3536,7 +3544,6 @@
       "vadd.s16    q0, q0, q1                    \n"
       "vld1.8      {d2}, [%0],%5                 \n"  // right
       "vld1.8      {d3}, [%1],%5                 \n"
-      "subs        %3, %3, #8                    \n"  // 8 pixels
       "vsubl.u8    q1, d2, d3                    \n"
       "vadd.s16    q0, q0, q1                    \n"
       "vabs.s16    q0, q0                        \n"
@@ -3554,59 +3561,41 @@
 }
 
 // %y passes a float as a scalar vector for vector * scalar multiply.
-// the regoster must be d0 to d15 and indexed with [0] or [1] to access
+// the register must be d0 to d15 and indexed with [0] or [1] to access
 // the float in the first or second float of the d-reg
 
-void HalfFloat1Row_NEON(const uint16_t* src,
-                        uint16_t* dst,
-                        float /*unused*/,
-                        int width) {
-  asm volatile(
-
-      "1:                                        \n"
-      "vld1.8      {q1}, [%0]!                   \n"  // load 8 shorts
-      "subs        %2, %2, #8                    \n"  // 8 pixels per loop
-      "vmovl.u16   q2, d2                        \n"  // 8 int's
-      "vmovl.u16   q3, d3                        \n"
-      "vcvt.f32.u32 q2, q2                       \n"  // 8 floats
-      "vcvt.f32.u32 q3, q3                       \n"
-      "vmul.f32    q2, q2, %y3                   \n"  // adjust exponent
-      "vmul.f32    q3, q3, %y3                   \n"
-      "vqshrn.u32  d2, q2, #13                   \n"  // isolate halffloat
-      "vqshrn.u32  d3, q3, #13                   \n"
-      "vst1.8      {q1}, [%1]!                   \n"
-      "bgt         1b                            \n"
-      : "+r"(src),              // %0
-        "+r"(dst),              // %1
-        "+r"(width)             // %2
-      : "w"(1.9259299444e-34f)  // %3
-      : "cc", "memory", "q1", "q2", "q3");
-}
-
 void HalfFloatRow_NEON(const uint16_t* src,
                        uint16_t* dst,
                        float scale,
                        int width) {
   asm volatile(
 
-      "1:                                        \n"
-      "vld1.8      {q1}, [%0]!                   \n"  // load 8 shorts
-      "subs        %2, %2, #8                    \n"  // 8 pixels per loop
-      "vmovl.u16   q2, d2                        \n"  // 8 int's
-      "vmovl.u16   q3, d3                        \n"
-      "vcvt.f32.u32 q2, q2                       \n"  // 8 floats
-      "vcvt.f32.u32 q3, q3                       \n"
-      "vmul.f32    q2, q2, %y3                   \n"  // adjust exponent
-      "vmul.f32    q3, q3, %y3                   \n"
-      "vqshrn.u32  d2, q2, #13                   \n"  // isolate halffloat
-      "vqshrn.u32  d3, q3, #13                   \n"
-      "vst1.8      {q1}, [%1]!                   \n"
+      "1:          \n"
+      "vld1.16     {q0, q1}, [%0]!               \n"  // load 16 shorts
+      "subs        %2, %2, #16                   \n"  // 16 pixels per loop
+      "vmovl.u16   q8, d0                        \n"
+      "vmovl.u16   q9, d1                        \n"
+      "vmovl.u16   q10, d2                       \n"
+      "vmovl.u16   q11, d3                       \n"
+      "vcvt.f32.u32 q8, q8                       \n"
+      "vcvt.f32.u32 q9, q9                       \n"
+      "vcvt.f32.u32 q10, q10                     \n"
+      "vcvt.f32.u32 q11, q11                     \n"
+      "vmul.f32    q8, q8, %y3                   \n"  // adjust exponent
+      "vmul.f32    q9, q9, %y3                   \n"
+      "vmul.f32    q10, q10, %y3                 \n"
+      "vmul.f32    q11, q11, %y3                 \n"
+      "vqshrn.u32  d0, q8, #13                   \n"  // isolate halffloat
+      "vqshrn.u32  d1, q9, #13                   \n"
+      "vqshrn.u32  d2, q10, #13                  \n"
+      "vqshrn.u32  d3, q11, #13                  \n"
+      "vst1.16     {q0, q1}, [%1]!               \n"  // store 16 fp16
       "bgt         1b                            \n"
       : "+r"(src),                      // %0
         "+r"(dst),                      // %1
         "+r"(width)                     // %2
       : "w"(scale * 1.9259299444e-34f)  // %3
-      : "cc", "memory", "q1", "q2", "q3");
+      : "cc", "memory", "q0", "q1", "q8", "q9", "q10", "q11");
 }
 
 void ByteToFloatRow_NEON(const uint8_t* src,
@@ -3615,7 +3604,7 @@
                          int width) {
   asm volatile(
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d2}, [%0]!                   \n"  // load 8 bytes
       "subs        %2, %2, #8                    \n"  // 8 pixels per loop
       "vmovl.u8    q1, d2                        \n"  // 8 shorts
@@ -3646,9 +3635,10 @@
       "vmov.u16    d6, #4                        \n"  // constant 4
       "vmov.u16    d7, #6                        \n"  // constant 6
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q1}, [%0]!                   \n"  // load 8 samples, 5 rows
       "vld1.16     {q2}, [%4]!                   \n"
+      "subs        %6, %6, #8                    \n"  // 8 processed per loop
       "vaddl.u16   q0, d2, d4                    \n"  // * 1
       "vaddl.u16   q1, d3, d5                    \n"  // * 1
       "vld1.16     {q2}, [%1]!                   \n"
@@ -3660,7 +3650,6 @@
       "vld1.16     {q2}, [%3]!                   \n"
       "vmlal.u16   q0, d4, d6                    \n"  // * 4
       "vmlal.u16   q1, d5, d6                    \n"  // * 4
-      "subs        %6, %6, #8                    \n"  // 8 processed per loop
       "vst1.32     {q0, q1}, [%5]!               \n"  // store 8 samples
       "bgt         1b                            \n"
       : "+r"(src0),  // %0
@@ -3683,9 +3672,10 @@
       "vmov.u32    q10, #4                       \n"  // constant 4
       "vmov.u32    q11, #6                       \n"  // constant 6
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.32     {q0, q1}, [%0]!               \n"  // load 12 source samples
       "vld1.32     {q2}, [%0]                    \n"
+      "subs        %5, %5, #8                    \n"  // 8 processed per loop
       "vadd.u32    q0, q0, q1                    \n"  // * 1
       "vadd.u32    q1, q1, q2                    \n"  // * 1
       "vld1.32     {q2, q3}, [%2]!               \n"
@@ -3697,7 +3687,6 @@
       "vadd.u32    q3, q3, q9                    \n"
       "vmla.u32    q0, q2, q10                   \n"  // * 4
       "vmla.u32    q1, q3, q10                   \n"  // * 4
-      "subs        %5, %5, #8                    \n"  // 8 processed per loop
       "vqshrn.u32  d0, q0, #8                    \n"  // round and pack
       "vqshrn.u32  d1, q1, #8                    \n"
       "vst1.u16    {q0}, [%4]!                   \n"  // store 8 samples
@@ -3718,14 +3707,14 @@
                          uint8_t* dst_yuv24,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q2}, [%0]!                   \n"  // load 16 Y values
       "vld2.8      {d0, d2}, [%1]!               \n"  // load 8 VU values
+      "subs        %3, %3, #16                   \n"  // 16 pixels per loop
       "vmov        d1, d0                        \n"
       "vzip.u8     d0, d1                        \n"  // VV
       "vmov        d3, d2                        \n"
       "vzip.u8     d2, d3                        \n"  // UU
-      "subs        %3, %3, #16                   \n"  // 16 pixels per loop
       "vst3.8      {d0, d2, d4}, [%2]!           \n"  // store 16 YUV pixels
       "vst3.8      {d1, d3, d5}, [%2]!           \n"
       "bgt         1b                            \n"
@@ -3743,10 +3732,11 @@
                       int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // src_stride + src_AYUV
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 AYUV pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 AYUV
                                                       // pixels.
+      "subs        %3, %3, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // V 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // U 16 bytes -> 8 shorts.
       "vld4.8      {d8, d10, d12, d14}, [%1]!    \n"  // load 8 more AYUV
@@ -3757,7 +3747,6 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vqrshrun.s16 d1, q0, #2                   \n"  // 2x2 average
       "vqrshrun.s16 d0, q1, #2                   \n"
-      "subs        %3, %3, #16                   \n"  // 16 processed per loop.
       "vst2.8      {d0, d1}, [%2]!               \n"  // store 8 pixels UV.
       "bgt         1b                            \n"
       : "+r"(src_ayuv),         // %0
@@ -3774,10 +3763,11 @@
                       int width) {
   asm volatile(
       "add         %1, %0, %1                    \n"  // src_stride + src_AYUV
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 AYUV pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 AYUV
                                                       // pixels.
+      "subs        %3, %3, #16                   \n"  // 16 processed per loop.
       "vpaddl.u8   q0, q0                        \n"  // V 16 bytes -> 8 shorts.
       "vpaddl.u8   q1, q1                        \n"  // U 16 bytes -> 8 shorts.
       "vld4.8      {d8, d10, d12, d14}, [%1]!    \n"  // load 8 more AYUV
@@ -3788,7 +3778,6 @@
       "vpadal.u8   q1, q5                        \n"  // G 16 bytes -> 8 shorts.
       "vqrshrun.s16 d0, q0, #2                   \n"  // 2x2 average
       "vqrshrun.s16 d1, q1, #2                   \n"
-      "subs        %3, %3, #16                   \n"  // 16 processed per loop.
       "vst2.8      {d0, d1}, [%2]!               \n"  // store 8 pixels VU.
       "bgt         1b                            \n"
       : "+r"(src_ayuv),         // %0
@@ -3803,7 +3792,7 @@
 // Similar to ARGBExtractAlphaRow_NEON
 void AYUVToYRow_NEON(const uint8_t* src_ayuv, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 AYUV pixels
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 AYUV pixels
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
@@ -3819,11 +3808,11 @@
 // Convert UV plane of NV12 to VU of NV21.
 void SwapUVRow_NEON(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d2}, [%0]!               \n"  // load 16 UV values
       "vld2.8      {d1, d3}, [%0]!               \n"
-      "vorr.u8     q2, q0, q0                    \n"  // move U after V
       "subs        %2, %2, #16                   \n"  // 16 pixels per loop
+      "vmov.u8     q2, q0                        \n"  // move U after V
       "vst2.8      {q1, q2}, [%1]!               \n"  // store 16 VU pixels
       "bgt         1b                            \n"
       : "+r"(src_uv),  // %0
@@ -3842,18 +3831,18 @@
   const uint8_t* src_u_1 = src_u + src_stride_u;
   const uint8_t* src_v_1 = src_v + src_stride_v;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load 16 U values
       "vld1.8      {q1}, [%2]!                   \n"  // load 16 V values
       "vld1.8      {q2}, [%1]!                   \n"
       "vld1.8      {q3}, [%3]!                   \n"
+      "subs        %5, %5, #16                   \n"  // 16 src pixels per loop
       "vpaddl.u8   q0, q0                        \n"  // half size
       "vpaddl.u8   q1, q1                        \n"
       "vpadal.u8   q0, q2                        \n"
       "vpadal.u8   q1, q3                        \n"
       "vqrshrn.u16 d0, q0, #2                    \n"
       "vqrshrn.u16 d1, q1, #2                    \n"
-      "subs        %5, %5, #16                   \n"  // 16 src pixels per loop
       "vst2.8      {d0, d1}, [%4]!               \n"  // store 8 UV pixels
       "bgt         1b                            \n"
       : "+r"(src_u),    // %0
@@ -3874,11 +3863,11 @@
   int shift = depth - 16;  // Negative for right shift.
   asm volatile(
       "vdup.16     q2, %4                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld2.16     {q0, q1}, [%0]!               \n"  // load 8 UV
+      "subs        %3, %3, #8                    \n"  // 8 src pixels per loop
       "vshl.u16    q0, q0, q2                    \n"
       "vshl.u16    q1, q1, q2                    \n"
-      "subs        %3, %3, #8                    \n"  // 8 src pixels per loop
       "vst1.16     {q0}, [%1]!                   \n"  // store 8 U pixels
       "vst1.16     {q1}, [%2]!                   \n"  // store 8 V pixels
       "bgt         1b                            \n"
@@ -3898,12 +3887,12 @@
   int shift = 16 - depth;
   asm volatile(
       "vdup.16     q2, %4                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"  // load 8 U
       "vld1.16     {q1}, [%1]!                   \n"  // load 8 V
+      "subs        %3, %3, #8                    \n"  // 8 src pixels per loop
       "vshl.u16    q0, q0, q2                    \n"
       "vshl.u16    q1, q1, q2                    \n"
-      "subs        %3, %3, #8                    \n"  // 8 src pixels per loop
       "vst2.16     {q0, q1}, [%2]!               \n"  // store 8 UV pixels
       "bgt         1b                            \n"
       : "+r"(src_u),   // %0
@@ -3920,14 +3909,14 @@
                          int width) {
   asm volatile(
       "vdup.16     q2, %3                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"
       "vld1.16     {q1}, [%0]!                   \n"
+      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "vmul.u16    q0, q0, q2                    \n"
       "vmul.u16    q1, q1, q2                    \n"
       "vst1.16     {q0}, [%1]!                   \n"
       "vst1.16     {q1}, [%1]!                   \n"
-      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "bgt         1b                            \n"
       : "+r"(src_y),  // %0
         "+r"(dst_y),  // %1
@@ -3942,8 +3931,9 @@
                        int width) {
   asm volatile(
       "vdup.16     d8, %3                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q2, q3}, [%0]!               \n"
+      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "vmull.u16   q0, d4, d8                    \n"
       "vmull.u16   q1, d5, d8                    \n"
       "vmull.u16   q2, d6, d8                    \n"
@@ -3953,7 +3943,6 @@
       "vshrn.u32   d2, q2, #16                   \n"
       "vshrn.u32   d3, q3, #16                   \n"
       "vst1.16     {q0, q1}, [%1]!               \n"  // store 16 pixels
-      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "bgt         1b                            \n"
       : "+r"(src_y),  // %0
         "+r"(dst_y),  // %1
@@ -3974,14 +3963,14 @@
   int shift = 15 - __builtin_clz((int32_t)scale);  // Negative shl is shr
   asm volatile(
       "vdup.16     q2, %3                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"
       "vld1.16     {q1}, [%0]!                   \n"
+      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "vshl.u16    q0, q0, q2                    \n"  // shr = q2 is negative
       "vshl.u16    q1, q1, q2                    \n"
       "vqmovn.u16  d0, q0                        \n"
       "vqmovn.u16  d1, q1                        \n"
-      "subs        %2, %2, #16                   \n"  // 16 src pixels per loop
       "vst1.8      {q0}, [%1]!                   \n"
       "bgt         1b                            \n"
       : "+r"(src_y),  // %0
@@ -3991,6 +3980,41 @@
       : "cc", "memory", "q0", "q1", "q2");
 }
 
+// Use scale to convert J420 to I420
+// scale parameter is 8.8 fixed point but limited to 0 to 255
+// Function is based on DivideRow, but adds a bias
+// Does not clamp
+void Convert8To8Row_NEON(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width) {
+  asm volatile(
+      "vdup.8      d8, %3                        \n"
+      "vdup.8      q5, %4                        \n"
+      "1:          \n"
+      "vld1.8      {q2, q3}, [%0]!               \n"
+      "subs        %2, %2, #32                   \n"  // 32 src pixels per loop
+      "vmull.u8    q0, d4, d8                    \n"
+      "vmull.u8    q1, d5, d8                    \n"
+      "vmull.u8    q2, d6, d8                    \n"
+      "vmull.u8    q3, d7, d8                    \n"
+      "vshrn.u16   d0, q0, #8                    \n"
+      "vshrn.u16   d1, q1, #8                    \n"
+      "vshrn.u16   d2, q2, #8                    \n"
+      "vshrn.u16   d3, q3, #8                    \n"
+      "vadd.u8     q0, q0, q5                    \n"
+      "vadd.u8     q1, q1, q5                    \n"
+      "vst1.8      {q0, q1}, [%1]!               \n"  // store 32 pixels
+      "bgt         1b                            \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale),   // %3
+        "r"(bias)     // %4
+      : "cc", "memory", "q0", "q1", "q2", "q3", "d8", "q5");
+}
+
 #endif  // !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)..
 
 #ifdef __cplusplus
diff --git a/source/row_neon64.cc b/source/row_neon64.cc
index 1679f87..0a0427c 100644
--- a/source/row_neon64.cc
+++ b/source/row_neon64.cc
@@ -28,35 +28,96 @@
 // Read 8 Y, 4 U and 4 V from 422
 #define READYUV422                               \
   "ldr        d0, [%[src_y]], #8             \n" \
-  "ld1        {v1.s}[0], [%[src_u]], #4      \n" \
-  "ld1        {v1.s}[1], [%[src_v]], #4      \n" \
+  "ldr        s1, [%[src_u]], #4             \n" \
+  "ldr        s2, [%[src_v]], #4             \n" \
   "zip1       v0.16b, v0.16b, v0.16b         \n" \
   "prfm       pldl1keep, [%[src_y], 448]     \n" \
-  "zip1       v1.16b, v1.16b, v1.16b         \n" \
+  "zip1       v1.8b, v1.8b, v1.8b            \n" \
+  "zip1       v2.8b, v2.8b, v2.8b            \n" \
   "prfm       pldl1keep, [%[src_u], 128]     \n" \
   "prfm       pldl1keep, [%[src_v], 128]     \n"
 
+// Read 8 Y, 4 U and 4 V from 210
+#define READYUV210                               \
+  "ldr        q2, [%[src_y]], #16            \n" \
+  "ldr        d1, [%[src_u]], #8             \n" \
+  "ldr        d3, [%[src_v]], #8             \n" \
+  "shl        v0.8h, v2.8h, #6               \n" \
+  "usra       v0.8h, v2.8h, #4               \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "zip1       v2.8h, v3.8h, v3.8h            \n" \
+  "zip1       v3.8h, v1.8h, v1.8h            \n" \
+  "uqshrn     v1.8b, v3.8h, #2               \n" \
+  "uqshrn2    v1.16b, v2.8h, #2              \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n"
+
+// Read 8 Y, 4 U and 4 V interleaved from 210
+#define READYUVP210                              \
+  "ldr        q0, [%[src_y]], #16            \n" \
+  "ldr        q1, [%[src_uv]], #16           \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "tbl        v1.16b, {v1.16b}, v2.16b       \n"
+
+// Read 8 Y, 4 U and 4 V from 212
+#define READYUV212                               \
+  "ldr        q2, [%[src_y]], #16            \n" \
+  "ldr        d1, [%[src_u]], #8             \n" \
+  "ldr        d3, [%[src_v]], #8             \n" \
+  "shl        v0.8h, v2.8h, #4               \n" \
+  "usra       v0.8h, v2.8h, #8               \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "zip1       v2.8h, v3.8h, v3.8h            \n" \
+  "zip1       v3.8h, v1.8h, v1.8h            \n" \
+  "uqshrn     v1.8b, v3.8h, #4               \n" \
+  "uqshrn2    v1.16b, v2.8h, #4              \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n"
+
+// Read 8 Y, 8 U and 8 V from 410
+#define READYUV410                               \
+  "ldr        q1, [%[src_y]], #16            \n" \
+  "ldr        q2, [%[src_u]], #16            \n" \
+  "ldr        q3, [%[src_v]], #16            \n" \
+  "shl        v0.8h, v1.8h, #6               \n" \
+  "usra       v0.8h, v1.8h, #4               \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "uqshrn     v1.8b, v2.8h, #2               \n" \
+  "uqshrn2    v1.16b, v3.8h, #2              \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n"
+
+// Read 8 Y, 8 U and 8 V interleaved from 410
+#define READYUVP410                                \
+  "ldr        q0, [%[src_y]], #16              \n" \
+  "ldp        q4, q5, [%[src_uv]], #32         \n" \
+  "prfm       pldl1keep, [%[src_y], 448]       \n" \
+  "tbl        v1.16b, {v4.16b, v5.16b}, v2.16b \n"
+
 // Read 8 Y, 8 U and 8 V from 444
 #define READYUV444                               \
   "ldr        d0, [%[src_y]], #8             \n" \
-  "ld1        {v1.d}[0], [%[src_u]], #8      \n" \
+  "ldr        d1, [%[src_u]], #8             \n" \
+  "ldr        d2, [%[src_v]], #8             \n" \
   "prfm       pldl1keep, [%[src_y], 448]     \n" \
-  "ld1        {v1.d}[1], [%[src_v]], #8      \n" \
   "prfm       pldl1keep, [%[src_u], 448]     \n" \
   "zip1       v0.16b, v0.16b, v0.16b         \n" \
   "prfm       pldl1keep, [%[src_v], 448]     \n"
 
-// Read 8 Y, and set 4 U and 4 V to 128
+// Read 8 Y
 #define READYUV400                               \
   "ldr        d0, [%[src_y]], #8             \n" \
-  "movi       v1.16b, #128                   \n" \
   "prfm       pldl1keep, [%[src_y], 448]     \n" \
   "zip1       v0.16b, v0.16b, v0.16b         \n"
 
 static const uvec8 kNV12Table = {0, 0, 2, 2, 4, 4, 6, 6,
                                  1, 1, 3, 3, 5, 5, 7, 7};
+static const uvec8 kNV12InterleavedTable = {0, 0, 4, 4, 8,  8,  12, 12,
+                                            2, 2, 6, 6, 10, 10, 14, 14};
 static const uvec8 kNV21Table = {1, 1, 3, 3, 5, 5, 7, 7,
                                  0, 0, 2, 2, 4, 4, 6, 6};
+static const uvec8 kNV21InterleavedTable = {1, 1, 5, 5, 9,  9,  13, 13,
+                                            3, 3, 7, 7, 11, 11, 15, 15};
 
 // Read 8 Y and 4 UV from NV12 or NV21
 #define READNV12                                 \
@@ -68,17 +129,17 @@
   "prfm       pldl1keep, [%[src_uv], 448]    \n"
 
 // Read 8 YUY2
-#define READYUY2                                     \
-  "ld2        {v0.8b, v1.8b}, [%[src_yuy2]], #16 \n" \
-  "zip1       v0.16b, v0.16b, v0.16b         \n"     \
-  "prfm       pldl1keep, [%[src_yuy2], 448]  \n"     \
-  "tbl        v1.16b, {v1.16b}, v2.16b       \n"
+#define READYUY2                                 \
+  "ld1        {v3.16b}, [%[src_yuy2]], #16   \n" \
+  "trn1       v0.16b, v3.16b, v3.16b         \n" \
+  "prfm       pldl1keep, [%[src_yuy2], 448]  \n" \
+  "tbl        v1.16b, {v3.16b}, v2.16b       \n"
 
 // Read 8 UYVY
-#define READUYVY                                     \
-  "ld2        {v3.8b, v4.8b}, [%[src_uyvy]], #16 \n" \
-  "zip1       v0.16b, v4.16b, v4.16b         \n"     \
-  "prfm       pldl1keep, [%[src_uyvy], 448]  \n"     \
+#define READUYVY                                 \
+  "ld1        {v3.16b}, [%[src_uyvy]], #16   \n" \
+  "trn2       v0.16b, v3.16b, v3.16b         \n" \
+  "prfm       pldl1keep, [%[src_uyvy], 448]  \n" \
   "tbl        v1.16b, {v3.16b}, v2.16b       \n"
 
 // UB VR UG VG
@@ -91,14 +152,14 @@
 // v17.8h: G
 // v18.8h: R
 
-// Convert from YUV to 2.14 fixed point RGB
-#define YUVTORGB                                          \
+// Convert from YUV (NV12 or NV21) to 2.14 fixed point RGB.
+// Similar to I4XXTORGB but U/V components are in the low/high halves of v1.
+#define NVTORGB                                           \
   "umull2     v3.4s, v0.8h, v24.8h           \n"          \
   "umull      v6.8h, v1.8b, v30.8b           \n"          \
   "umull      v0.4s, v0.4h, v24.4h           \n"          \
   "umlal2     v6.8h, v1.16b, v31.16b         \n" /* DG */ \
-  "uqshrn     v0.4h, v0.4s, #16              \n"          \
-  "uqshrn2    v0.8h, v3.4s, #16              \n" /* Y */  \
+  "uzp2       v0.8h, v0.8h, v3.8h            \n" /* Y */  \
   "umull      v4.8h, v1.8b, v28.8b           \n" /* DB */ \
   "umull2     v5.8h, v1.16b, v29.16b         \n" /* DR */ \
   "add        v17.8h, v0.8h, v26.8h          \n" /* G */  \
@@ -108,15 +169,69 @@
   "uqsub      v16.8h, v16.8h, v25.8h         \n" /* B */  \
   "uqsub      v18.8h, v18.8h, v27.8h         \n" /* R */
 
+// Convert from YUV (I444 or I420) to 2.14 fixed point RGB.
+// Similar to NVTORGB but U/V components are in v1/v2.
+#define I4XXTORGB                                         \
+  "umull2     v3.4s, v0.8h, v24.8h           \n"          \
+  "umull      v6.8h, v1.8b, v30.8b           \n"          \
+  "umull      v0.4s, v0.4h, v24.4h           \n"          \
+  "umlal      v6.8h, v2.8b, v31.8b           \n" /* DG */ \
+  "uzp2       v0.8h, v0.8h, v3.8h            \n" /* Y */  \
+  "umull      v4.8h, v1.8b, v28.8b           \n" /* DB */ \
+  "umull      v5.8h, v2.8b, v29.8b           \n" /* DR */ \
+  "add        v17.8h, v0.8h, v26.8h          \n" /* G */  \
+  "add        v16.8h, v0.8h, v4.8h           \n" /* B */  \
+  "add        v18.8h, v0.8h, v5.8h           \n" /* R */  \
+  "uqsub      v17.8h, v17.8h, v6.8h          \n" /* G */  \
+  "uqsub      v16.8h, v16.8h, v25.8h         \n" /* B */  \
+  "uqsub      v18.8h, v18.8h, v27.8h         \n" /* R */
+
+// Convert from YUV I400 to 2.14 fixed point RGB
+#define I400TORGB                                        \
+  "umull2     v3.4s, v0.8h, v24.8h           \n"         \
+  "umull      v0.4s, v0.4h, v24.4h           \n"         \
+  "uzp2       v0.8h, v0.8h, v3.8h            \n" /* Y */ \
+  "add        v17.8h, v0.8h, v26.8h          \n" /* G */ \
+  "add        v16.8h, v0.8h, v4.8h           \n" /* B */ \
+  "add        v18.8h, v0.8h, v5.8h           \n" /* R */ \
+  "uqsub      v17.8h, v17.8h, v6.8h          \n" /* G */ \
+  "uqsub      v16.8h, v16.8h, v25.8h         \n" /* B */ \
+  "uqsub      v18.8h, v18.8h, v27.8h         \n" /* R */
+
 // Convert from 2.14 fixed point RGB To 8 bit RGB
 #define RGBTORGB8                                \
   "uqshrn     v17.8b, v17.8h, #6             \n" \
   "uqshrn     v16.8b, v16.8h, #6             \n" \
   "uqshrn     v18.8b, v18.8h, #6             \n"
 
-#define YUVTORGB_REGS                                                          \
-  "v0", "v1", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v24", "v25", \
-      "v26", "v27", "v28", "v29", "v30", "v31"
+// Convert from 2.14 fixed point RGB to 8 bit RGB, placing the results in the
+// top half of each lane.
+#define RGBTORGB8_TOP                            \
+  "uqshl      v17.8h, v17.8h, #2             \n" \
+  "uqshl      v16.8h, v16.8h, #2             \n" \
+  "uqshl      v18.8h, v18.8h, #2             \n"
+
+// Store 2.14 fixed point RGB as AR30 elements
+#define STOREAR30                                                         \
+  /* Inputs:                                                              \
+   *   v16.8h: xxbbbbbbbbbbxxxx                                           \
+   *   v17.8h: xxggggggggggxxxx                                           \
+   *   v18.8h: xxrrrrrrrrrrxxxx                                           \
+   *   v22.8h: 0011111111110000 (umin limit)                              \
+   *   v23.8h: 1100000000000000 (alpha)                                   \
+   */                                                                     \
+  "uqshl    v0.8h, v16.8h, #2                  \n" /* bbbbbbbbbbxxxxxx */ \
+  "uqshl    v1.8h, v17.8h, #2                  \n" /* ggggggggggxxxxxx */ \
+  "umin     v6.8h, v18.8h, v22.8h              \n" /* 00rrrrrrrrrrxxxx */ \
+  "shl      v4.8h, v1.8h, #4                   \n" /* ggggggxxxxxx0000 */ \
+  "orr      v5.16b, v6.16b, v23.16b            \n" /* 11rrrrrrrrrrxxxx */ \
+  "sri      v4.8h, v0.8h, #6                   \n" /* ggggggbbbbbbbbbb */ \
+  "sri      v5.8h, v1.8h, #12                  \n" /* 11rrrrrrrrrrgggg */ \
+  "st2      {v4.8h, v5.8h}, [%[dst_ar30]], #32 \n"
+
+#define YUVTORGB_REGS                                                         \
+  "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v24", \
+      "v25", "v26", "v27", "v28", "v29", "v30", "v31"
 
 void I444ToARGBRow_NEON(const uint8_t* src_y,
                         const uint8_t* src_u,
@@ -127,9 +242,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "movi        v19.8b, #255                  \n" /* A */
-      "1:                                        \n" READYUV444 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"                               //
+      READYUV444
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -150,9 +265,9 @@
                          int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV444 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READYUV444
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
       "st3         {v16.8b,v17.8b,v18.8b}, [%[dst_rgb24]], #24 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -165,18 +280,103 @@
       : "cc", "memory", YUVTORGB_REGS);
 }
 
-void I422ToARGBRow_NEON(const uint8_t* src_y,
-                        const uint8_t* src_u,
-                        const uint8_t* src_v,
+void I210ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  uint16_t limit = 0x3ff0;
+  uint16_t alpha = 0xc000;
+  asm volatile(YUVTORGB_SETUP
+               "dup         v22.8h, %w[limit]             \n"
+               "dup         v23.8h, %w[alpha]             \n"
+               "1:          \n"  //
+               READYUV210
+               "subs        %w[width], %w[width], #8      \n" NVTORGB STOREAR30
+               "b.gt        1b                            \n"
+               : [src_y] "+r"(src_y),             // %[src_y]
+                 [src_u] "+r"(src_u),             // %[src_u]
+                 [src_v] "+r"(src_v),             // %[src_v]
+                 [dst_ar30] "+r"(dst_ar30),       // %[dst_ar30]
+                 [width] "+r"(width)              // %[width]
+               : [kUVCoeff] "r"(uv_coeff),        // %[kUVCoeff]
+                 [kRGBCoeffBias] "r"(rgb_coeff),  // %[kRGBCoeffBias]
+                 [limit] "r"(limit),              // %[limit]
+                 [alpha] "r"(alpha)               // %[alpha]
+               : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
+void I410ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  uint16_t limit = 0x3ff0;
+  uint16_t alpha = 0xc000;
+  asm volatile(YUVTORGB_SETUP
+               "dup         v22.8h, %w[limit]             \n"
+               "dup         v23.8h, %w[alpha]             \n"
+               "1:          \n"  //
+               READYUV410
+               "subs        %w[width], %w[width], #8      \n" NVTORGB STOREAR30
+               "b.gt        1b                            \n"
+               : [src_y] "+r"(src_y),             // %[src_y]
+                 [src_u] "+r"(src_u),             // %[src_u]
+                 [src_v] "+r"(src_v),             // %[src_v]
+                 [dst_ar30] "+r"(dst_ar30),       // %[dst_ar30]
+                 [width] "+r"(width)              // %[width]
+               : [kUVCoeff] "r"(uv_coeff),        // %[kUVCoeff]
+                 [kRGBCoeffBias] "r"(rgb_coeff),  // %[kRGBCoeffBias]
+                 [limit] "r"(limit),              // %[limit]
+                 [alpha] "r"(alpha)               // %[alpha]
+               : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
+void I212ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  const uint16_t limit = 0x3ff0;
+  asm volatile(YUVTORGB_SETUP
+               "dup         v22.8h, %w[limit]             \n"
+               "movi        v23.8h, #0xc0, lsl #8         \n"  // A
+               "1:          \n"                                //
+               READYUV212
+               "subs        %w[width], %w[width], #8      \n" NVTORGB STOREAR30
+               "b.gt        1b                            \n"
+               : [src_y] "+r"(src_y),             // %[src_y]
+                 [src_u] "+r"(src_u),             // %[src_u]
+                 [src_v] "+r"(src_v),             // %[src_v]
+                 [dst_ar30] "+r"(dst_ar30),       // %[dst_ar30]
+                 [width] "+r"(width)              // %[width]
+               : [kUVCoeff] "r"(uv_coeff),        // %[kUVCoeff]
+                 [kRGBCoeffBias] "r"(rgb_coeff),  // %[kRGBCoeffBias]
+                 [limit] "r"(limit)               // %[limit]
+               : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
+void I210ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
                         uint8_t* dst_argb,
                         const struct YuvConstants* yuvconstants,
                         int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "movi        v19.8b, #255                  \n" /* A */
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "movi        v19.8b, #255                  \n"
+      "1:          \n"  //
+      READYUV210
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -189,6 +389,220 @@
       : "cc", "memory", YUVTORGB_REGS, "v19");
 }
 
+void I410ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  asm volatile(
+      YUVTORGB_SETUP
+      "movi        v19.8b, #255                  \n"
+      "1:          \n"  //
+      READYUV410
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
+      "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width)                                // %[width]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+void I212ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  asm volatile(
+      YUVTORGB_SETUP
+      "movi        v19.8b, #255                  \n"
+      "1:          \n"  //
+      READYUV212
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
+      "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),            // %[src_y]
+        [src_u] "+r"(src_u),            // %[src_u]
+        [src_v] "+r"(src_v),            // %[src_v]
+        [dst_argb] "+r"(dst_argb),      // %[dst_argb]
+        [width] "+r"(width)             // %[width]
+      : [kUVCoeff] "r"(uv_coeff),       // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(rgb_coeff)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+void I422ToARGBRow_NEON(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  asm volatile(
+      YUVTORGB_SETUP
+      "movi        v19.8b, #255                  \n" /* A */
+      "1:          \n"                               //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
+      "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width)                                // %[width]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+uint8_t kP210LoadShuffleIndices[] = {1, 1, 5, 5, 9,  9,  13, 13,
+                                     3, 3, 7, 7, 11, 11, 15, 15};
+
+void P210ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  asm volatile(
+      YUVTORGB_SETUP
+      "movi        v19.8b, #255                  \n"
+      "ldr         q2, [%[kIndices]]             \n"
+      "1:          \n"  //
+      READYUVP210
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
+      "st4         {v16.8b, v17.8b, v18.8b, v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                     // %[src_y]
+        [src_uv] "+r"(src_uv),                   // %[src_uv]
+        [dst_argb] "+r"(dst_argb),               // %[dst_argb]
+        [width] "+r"(width)                      // %[width]
+      : [kUVCoeff] "r"(uv_coeff),                // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(rgb_coeff),          // %[kRGBCoeffBias]
+        [kIndices] "r"(kP210LoadShuffleIndices)  // %[kIndices]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+uint8_t kP410LoadShuffleIndices[] = {1, 5, 9,  13, 17, 21, 25, 29,
+                                     3, 7, 11, 15, 19, 23, 27, 31};
+
+void P410ToARGBRow_NEON(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  asm volatile(
+      YUVTORGB_SETUP
+      "movi        v19.8b, #255                  \n"
+      "ldr         q2, [%[kIndices]]             \n"
+      "1:          \n"  //
+      READYUVP410
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
+      "st4         {v16.8b, v17.8b, v18.8b, v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                     // %[src_y]
+        [src_uv] "+r"(src_uv),                   // %[src_uv]
+        [dst_argb] "+r"(dst_argb),               // %[dst_argb]
+        [width] "+r"(width)                      // %[width]
+      : [kUVCoeff] "r"(uv_coeff),                // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(rgb_coeff),          // %[kRGBCoeffBias]
+        [kIndices] "r"(kP410LoadShuffleIndices)  // %[kIndices]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+void P210ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  const uint16_t limit = 0x3ff0;
+  asm volatile(YUVTORGB_SETUP
+               "dup         v22.8h, %w[limit]             \n"
+               "movi        v23.8h, #0xc0, lsl #8         \n"  // A
+               "ldr         q2, [%[kIndices]]             \n"
+               "1:          \n"  //
+               READYUVP210
+               "subs        %w[width], %w[width], #8      \n" NVTORGB STOREAR30
+               "b.gt        1b                            \n"
+               : [src_y] "+r"(src_y),                     // %[src_y]
+                 [src_uv] "+r"(src_uv),                   // %[src_uv]
+                 [dst_ar30] "+r"(dst_ar30),               // %[dst_ar30]
+                 [width] "+r"(width)                      // %[width]
+               : [kUVCoeff] "r"(uv_coeff),                // %[kUVCoeff]
+                 [kRGBCoeffBias] "r"(rgb_coeff),          // %[kRGBCoeffBias]
+                 [limit] "r"(limit),                      // %[limit]
+                 [kIndices] "r"(kP210LoadShuffleIndices)  // %[kIndices]
+               : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
+void P410ToAR30Row_NEON(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  uint16_t limit = 0x3ff0;
+  asm volatile(YUVTORGB_SETUP
+               "dup         v22.8h, %w[limit]             \n"
+               "movi        v23.8h, #0xc0, lsl #8         \n"  // A
+               "ldr         q2, [%[kIndices]]             \n"
+               "1:          \n"  //
+               READYUVP410
+               "subs        %w[width], %w[width], #8      \n" NVTORGB STOREAR30
+               "b.gt        1b                            \n"
+               : [src_y] "+r"(src_y),                     // %[src_y]
+                 [src_uv] "+r"(src_uv),                   // %[src_uv]
+                 [dst_ar30] "+r"(dst_ar30),               // %[dst_ar30]
+                 [width] "+r"(width)                      // %[width]
+               : [kUVCoeff] "r"(uv_coeff),                // %[kUVCoeff]
+                 [kRGBCoeffBias] "r"(rgb_coeff),          // %[kRGBCoeffBias]
+                 [limit] "r"(limit),                      // %[limit]
+                 [kIndices] "r"(kP410LoadShuffleIndices)  // %[kIndices]
+               : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
+void I422ToAR30Row_NEON(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  const uvec8* uv_coeff = &yuvconstants->kUVCoeff;
+  const vec16* rgb_coeff = &yuvconstants->kRGBCoeffBias;
+  const uint16_t limit = 0x3ff0;
+  asm volatile(
+      YUVTORGB_SETUP
+      "dup         v22.8h, %w[limit]             \n"
+      "movi        v23.8h, #0xc0, lsl #8         \n"  // A
+      "1:          \n"                                //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB STOREAR30
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),             // %[src_y]
+        [src_u] "+r"(src_u),             // %[src_u]
+        [src_v] "+r"(src_v),             // %[src_v]
+        [dst_ar30] "+r"(dst_ar30),       // %[dst_ar30]
+        [width] "+r"(width)              // %[width]
+      : [kUVCoeff] "r"(uv_coeff),        // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(rgb_coeff),  // %[kRGBCoeffBias]
+        [limit] "r"(limit)               // %[limit]
+      : "cc", "memory", YUVTORGB_REGS, "v22", "v23");
+}
+
 void I444AlphaToARGBRow_NEON(const uint8_t* src_y,
                              const uint8_t* src_u,
                              const uint8_t* src_v,
@@ -198,10 +612,62 @@
                              int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v19.8b}, [%[src_a]], #8      \n" READYUV444
-      "prfm        pldl1keep, [%[src_a], 448]    \n" YUVTORGB RGBTORGB8
       "subs        %w[width], %w[width], #8      \n"
+      "prfm        pldl1keep, [%[src_a], 448]    \n" I4XXTORGB RGBTORGB8
+      "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [src_a] "+r"(src_a),                               // %[src_a]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width)                                // %[width]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+void I410AlphaToARGBRow_NEON(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  asm volatile(
+      YUVTORGB_SETUP
+      "1:          \n"
+      "ld1         {v19.16b}, [%[src_a]], #16    \n" READYUV410
+      "subs        %w[width], %w[width], #8      \n"
+      "uqshrn      v19.8b, v19.8h, #2            \n" NVTORGB RGBTORGB8
+      "st4         {v16.8b, v17.8b, v18.8b, v19.8b}, [%[dst_argb]], #32 \n"
+      "b.gt        1b                            \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [src_a] "+r"(src_a),                               // %[src_a]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width)                                // %[width]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_REGS, "v19");
+}
+
+void I210AlphaToARGBRow_NEON(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  asm volatile(
+      YUVTORGB_SETUP
+      "1:          \n"
+      "ld1         {v19.16b}, [%[src_a]], #16    \n" READYUV210
+      "subs        %w[width], %w[width], #8      \n"
+      "uqshrn      v19.8b, v19.8h, #2            \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -224,10 +690,10 @@
                              int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v19.8b}, [%[src_a]], #8      \n" READYUV422
-      "prfm        pldl1keep, [%[src_a], 448]    \n" YUVTORGB RGBTORGB8
       "subs        %w[width], %w[width], #8      \n"
+      "prfm        pldl1keep, [%[src_a], 448]    \n" I4XXTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -250,9 +716,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "movi        v15.8b, #255                  \n" /* A */
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"                               //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
       "st4         {v15.8b,v16.8b,v17.8b,v18.8b}, [%[dst_rgba]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -273,9 +739,9 @@
                          int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
       "st3         {v16.8b,v17.8b,v18.8b}, [%[dst_rgb24]], #24 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -288,12 +754,24 @@
       : "cc", "memory", YUVTORGB_REGS);
 }
 
-#define ARGBTORGB565                                                        \
-  "shll       v18.8h, v18.8b, #8             \n" /* R                    */ \
-  "shll       v17.8h, v17.8b, #8             \n" /* G                    */ \
-  "shll       v16.8h, v16.8b, #8             \n" /* B                    */ \
-  "sri        v18.8h, v17.8h, #5             \n" /* RG                   */ \
-  "sri        v18.8h, v16.8h, #11            \n" /* RGB                  */
+#define ARGBTORGB565                                                \
+  /* Inputs:                                                        \
+   * v16: bbbbbxxx                                                  \
+   * v17: ggggggxx                                                  \
+   * v18: rrrrrxxx */                                               \
+  "shll       v18.8h, v18.8b, #8     \n" /* rrrrrrxx00000000     */ \
+  "shll       v17.8h, v17.8b, #8     \n" /* gggggxxx00000000     */ \
+  "shll       v16.8h, v16.8b, #8     \n" /* bbbbbbxx00000000     */ \
+  "sri        v18.8h, v17.8h, #5     \n" /* rrrrrgggggg00000     */ \
+  "sri        v18.8h, v16.8h, #11    \n" /* rrrrrggggggbbbbb     */
+
+#define ARGBTORGB565_FROM_TOP                                       \
+  /* Inputs:                                                        \
+   * v16: bbbbbxxxxxxxxxxx                                          \
+   * v17: ggggggxxxxxxxxxx                                          \
+   * v18: rrrrrxxxxxxxxxxx */                                       \
+  "sri        v18.8h, v17.8h, #5     \n" /* rrrrrgggggg00000     */ \
+  "sri        v18.8h, v16.8h, #11    \n" /* rrrrrggggggbbbbb     */
 
 void I422ToRGB565Row_NEON(const uint8_t* src_y,
                           const uint8_t* src_u,
@@ -303,8 +781,10 @@
                           int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "1:                                        \n" READYUV422 YUVTORGB
-      RGBTORGB8 "subs        %w[width], %w[width], #8      \n" ARGBTORGB565
+      "1:          \n"  //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8_TOP
+          ARGBTORGB565_FROM_TOP
       "st1         {v18.8h}, [%[dst_rgb565]], #16 \n"  // store 8 pixels RGB565.
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -317,14 +797,22 @@
       : "cc", "memory", YUVTORGB_REGS);
 }
 
-#define ARGBTOARGB1555                                                      \
-  "shll       v0.8h,  v19.8b, #8             \n" /* A                    */ \
-  "shll       v18.8h, v18.8b, #8             \n" /* R                    */ \
-  "shll       v17.8h, v17.8b, #8             \n" /* G                    */ \
-  "shll       v16.8h, v16.8b, #8             \n" /* B                    */ \
-  "sri        v0.8h,  v18.8h, #1             \n" /* AR                   */ \
-  "sri        v0.8h,  v17.8h, #6             \n" /* ARG                  */ \
-  "sri        v0.8h,  v16.8h, #11            \n" /* ARGB                 */
+#define ARGBTOARGB1555                                                  \
+  /* Inputs:                                                            \
+   * v16: gggggxxxbbbbbxxx  v17: axxxxxxxrrrrrxxx  */                   \
+  "shl        v1.8h, v16.8h, #8              \n" /* bbbbbxxx00000000 */ \
+  "shl        v2.8h, v17.8h, #8              \n" /* rrrrrxxx00000000 */ \
+  "sri        v17.8h, v2.8h, #1              \n" /* arrrrrxxxrrrrxxx */ \
+  "sri        v17.8h, v16.8h, #6             \n" /* arrrrrgggggxxxbb */ \
+  "sri        v17.8h, v1.8h, #11             \n" /* arrrrrgggggbbbbb */
+
+#define ARGBTOARGB1555_FROM_TOP                                         \
+  /* Inputs:                                                            \
+   * v16: bbbbbxxxxxxxxxxx  v17: gggggxxxxxxxxxxx                       \
+   * v18: rrrrrxxxxxxxxxxx  v19: axxxxxxxxxxxxxxx */                    \
+  "sri        v19.8h,  v18.8h, #1            \n" /* arrrrrxxxxxxxxxx */ \
+  "sri        v19.8h,  v17.8h, #6            \n" /* arrrrrgggggxxxxx */ \
+  "sri        v19.8h,  v16.8h, #11           \n" /* arrrrrgggggbbbbb */
 
 void I422ToARGB1555Row_NEON(const uint8_t* src_y,
                             const uint8_t* src_u,
@@ -334,12 +822,12 @@
                             int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "movi        v19.8b, #255                  \n"
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n" ARGBTOARGB1555
-      "st1         {v0.8h}, [%[dst_argb1555]], #16 \n"  // store 8 pixels
-                                                        // RGB565.
+      "movi        v19.8h, #0x80, lsl #8         \n"
+      "1:          \n"                                           //
+      READYUV422 "subs        %w[width], %w[width], #8      \n"  //
+      I4XXTORGB RGBTORGB8_TOP ARGBTOARGB1555_FROM_TOP
+      "st1         {v19.8h}, [%[dst_argb1555]], #16 \n"  // store 8 pixels
+                                                         // RGB1555.
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
         [src_u] "+r"(src_u),                               // %[src_u]
@@ -351,15 +839,11 @@
       : "cc", "memory", YUVTORGB_REGS, "v19");
 }
 
-#define ARGBTOARGB4444                                                       \
-  /* Input v16.8b<=B, v17.8b<=G, v18.8b<=R, v19.8b<=A, v23.8b<=0x0f       */ \
-  "ushr       v16.8b, v16.8b, #4             \n" /* B                    */  \
-  "bic        v17.8b, v17.8b, v23.8b         \n" /* G                    */  \
-  "ushr       v18.8b, v18.8b, #4             \n" /* R                    */  \
-  "bic        v19.8b, v19.8b, v23.8b         \n" /* A                    */  \
-  "orr        v0.8b,  v16.8b, v17.8b         \n" /* BG                   */  \
-  "orr        v1.8b,  v18.8b, v19.8b         \n" /* RA                   */  \
-  "zip1       v0.16b, v0.16b, v1.16b         \n" /* BGRA                 */
+#define ARGBTOARGB4444                                   \
+  /* Input v16.8b<=B, v17.8b<=G, v18.8b<=R, v19.8b<=A */ \
+  "sri    v17.8b, v16.8b, #4       \n" /* BG */          \
+  "sri    v19.8b, v18.8b, #4       \n" /* RA */          \
+  "zip1   v0.16b, v17.16b, v19.16b \n" /* BGRA */
 
 void I422ToARGB4444Row_NEON(const uint8_t* src_y,
                             const uint8_t* src_u,
@@ -369,11 +853,9 @@
                             int width) {
   asm volatile(
       YUVTORGB_SETUP
-      "movi        v23.16b, #0x0f                \n"  // bits to clear with
-                                                      // vbic.
-      "1:                                        \n" READYUV422 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READYUV422
+      "subs        %w[width], %w[width], #8      \n" I4XXTORGB RGBTORGB8
       "movi        v19.8b, #255                  \n" ARGBTOARGB4444
       "st1         {v0.8h}, [%[dst_argb4444]], #16 \n"  // store 8
                                                         // pixels
@@ -386,7 +868,7 @@
         [width] "+r"(width)                                // %[width]
       : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
         [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
-      : "cc", "memory", YUVTORGB_REGS, "v19", "v23");
+      : "cc", "memory", YUVTORGB_REGS, "v19");
 }
 
 void I400ToARGBRow_NEON(const uint8_t* src_y,
@@ -395,10 +877,15 @@
                         int width) {
   asm volatile(
       YUVTORGB_SETUP
+      "movi        v1.16b, #128                  \n"
       "movi        v19.8b, #255                  \n"
-      "1:                                        \n" READYUV400 YUVTORGB
-          RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "umull       v6.8h, v1.8b, v30.8b          \n"
+      "umlal2      v6.8h, v1.16b, v31.16b        \n" /* DG */
+      "umull       v4.8h, v1.8b, v28.8b          \n" /* DB */
+      "umull2      v5.8h, v1.16b, v29.16b        \n" /* DR */
+      "1:          \n"                               //
+      READYUV400 I400TORGB
+      "subs        %w[width], %w[width], #8      \n" RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                               // %[src_y]
@@ -409,16 +896,16 @@
       : "cc", "memory", YUVTORGB_REGS, "v19");
 }
 
-#if LIBYUV_USE_ST4
+#if defined(LIBYUV_USE_ST4)
 void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) {
   asm volatile(
       "movi        v23.8b, #255                  \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v20.8b}, [%0], #8            \n"
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v21.8b, v20.8b, v20.8b        \n"
-      "orr         v22.8b, v20.8b, v20.8b        \n"
       "subs        %w2, %w2, #8                  \n"
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "mov         v21.8b, v20.8b                \n"
+      "mov         v22.8b, v20.8b                \n"
       "st4         {v20.8b,v21.8b,v22.8b,v23.8b}, [%1], #32 \n"
       "b.gt        1b                            \n"
       : "+r"(src_y),     // %0
@@ -431,7 +918,7 @@
 void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) {
   asm volatile(
       "movi        v20.8b, #255                  \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d16, [%0], #8                 \n"
       "subs        %w2, %w2, #8                  \n"
       "zip1        v18.16b, v16.16b, v16.16b     \n"  // YY
@@ -458,8 +945,8 @@
       YUVTORGB_SETUP
       "movi        v19.8b, #255                  \n"
       "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READNV12 "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                                // %[src_y]
@@ -481,8 +968,8 @@
       YUVTORGB_SETUP
       "movi        v19.8b, #255                  \n"
       "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READNV12 "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                                // %[src_y]
@@ -503,8 +990,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READNV12 "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st3         {v16.8b,v17.8b,v18.8b}, [%[dst_rgb24]], #24 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                                // %[src_y]
@@ -525,8 +1012,8 @@
   asm volatile(
       YUVTORGB_SETUP
       "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "1:          \n"  //
+      READNV12 "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st3         {v16.8b,v17.8b,v18.8b}, [%[dst_rgb24]], #24 \n"
       "b.gt        1b                            \n"
       : [src_y] "+r"(src_y),                                // %[src_y]
@@ -547,8 +1034,10 @@
   asm volatile(
       YUVTORGB_SETUP
       "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READNV12 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n" ARGBTORGB565
+      "1:          \n"  //
+      READNV12
+      "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8_TOP
+          ARGBTORGB565_FROM_TOP
       "st1         {v18.8h}, [%[dst_rgb565]], #16 \n"  // store 8
                                                        // pixels
                                                        // RGB565.
@@ -570,9 +1059,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "movi        v19.8b, #255                  \n"
-      "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READYUY2 YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "ldr         q2, [%[kNV21InterleavedTable]] \n"
+      "1:          \n"  //
+      READYUY2 "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_yuy2] "+r"(src_yuy2),                          // %[src_yuy2]
@@ -580,7 +1069,7 @@
         [width] "+r"(width)                                 // %[width]
       : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
         [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
-        [kNV12Table] "r"(&kNV12Table)
+        [kNV21InterleavedTable] "r"(&kNV21InterleavedTable)
       : "cc", "memory", YUVTORGB_REGS, "v2", "v19");
 }
 
@@ -591,9 +1080,9 @@
   asm volatile(
       YUVTORGB_SETUP
       "movi        v19.8b, #255                  \n"
-      "ldr         q2, [%[kNV12Table]]           \n"
-      "1:                                        \n" READUYVY YUVTORGB RGBTORGB8
-      "subs        %w[width], %w[width], #8      \n"
+      "ldr         q2, [%[kNV12InterleavedTable]] \n"
+      "1:          \n"  //
+      READUYVY "subs        %w[width], %w[width], #8      \n" NVTORGB RGBTORGB8
       "st4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%[dst_argb]], #32 \n"
       "b.gt        1b                            \n"
       : [src_uyvy] "+r"(src_uyvy),                          // %[src_yuy2]
@@ -601,7 +1090,7 @@
         [width] "+r"(width)                                 // %[width]
       : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),            // %[kUVCoeff]
         [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias),  // %[kRGBCoeffBias]
-        [kNV12Table] "r"(&kNV12Table)
+        [kNV12InterleavedTable] "r"(&kNV12InterleavedTable)
       : "cc", "memory", YUVTORGB_REGS, "v2", "v19");
 }
 
@@ -611,7 +1100,7 @@
                      uint8_t* dst_v,
                      int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"  // load 16 pairs of UV
       "subs        %w3, %w3, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -636,7 +1125,7 @@
                     uint8_t* dst,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], %3            \n"  // load 16 bytes
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 1792]         \n"  // 7 tiles of 256b ahead
@@ -656,7 +1145,7 @@
                        uint16_t* dst,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h,v1.8h}, [%0], %3       \n"  // load 16 pixels
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 3584]         \n"  // 7 tiles of 512b ahead
@@ -677,7 +1166,7 @@
                            uint8_t* dst_v,
                            int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.8b,v1.8b}, [%0], %4       \n"
       "subs        %w3, %w3, #16                 \n"
       "prfm        pldl1keep, [%0, 1792]         \n"
@@ -693,7 +1182,7 @@
   );
 }
 
-#if LIBYUV_USE_ST2
+#if defined(LIBYUV_USE_ST2)
 // Read 16 Y, 8 UV, and write 8 YUY2
 void DetileToYUY2_NEON(const uint8_t* src_y,
                        ptrdiff_t src_y_tile_stride,
@@ -702,12 +1191,12 @@
                        uint8_t* dst_yuy2,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], %4            \n"  // load 16 Ys
+      "subs        %w3, %w3, #16                 \n"  // store 8 YUY2
       "prfm        pldl1keep, [%0, 1792]         \n"
       "ld1         {v1.16b}, [%1], %5            \n"  // load 8 UVs
       "prfm        pldl1keep, [%1, 1792]         \n"
-      "subs        %w3, %w3, #16                 \n"  // store 8 YUY2
       "st2         {v0.16b,v1.16b}, [%2], #32    \n"
       "b.gt        1b                            \n"
       : "+r"(src_y),                // %0
@@ -728,7 +1217,7 @@
                        uint8_t* dst_yuy2,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], %4            \n"  // load 16 Ys
       "ld1         {v1.16b}, [%1], %5            \n"  // load 8 UVs
       "subs        %w3, %w3, #16                 \n"
@@ -753,13 +1242,13 @@
 // tinyurl.com/mtk-10bit-video-format for format documentation.
 void UnpackMT2T_NEON(const uint8_t* src, uint16_t* dst, size_t size) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v7.16b}, [%0], #16           \n"
       "ld1         {v0.16b-v3.16b}, [%0], #64    \n"
+      "subs        %2, %2, #80                   \n"
       "shl         v4.16b, v7.16b, #6            \n"
       "shl         v5.16b, v7.16b, #4            \n"
       "shl         v6.16b, v7.16b, #2            \n"
-      "subs        %2, %2, #80                   \n"
       "zip1        v16.16b, v4.16b, v0.16b       \n"
       "zip1        v18.16b, v5.16b, v1.16b       \n"
       "zip1        v20.16b, v6.16b, v2.16b       \n"
@@ -787,14 +1276,14 @@
         "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23");
 }
 
-#if LIBYUV_USE_ST2
+#if defined(LIBYUV_USE_ST2)
 // Reads 16 U's and V's and writes out 16 pairs of UV.
 void MergeUVRow_NEON(const uint8_t* src_u,
                      const uint8_t* src_v,
                      uint8_t* dst_uv,
                      int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load U
       "ld1         {v1.16b}, [%1], #16           \n"  // load V
       "subs        %w3, %w3, #16                 \n"  // 16 processed per loop
@@ -819,10 +1308,10 @@
   int shift = 16 - depth;
   asm volatile(
       "dup         v2.8h, %w4                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%0], #16            \n"  // load 8 U
-      "subs        %w3, %w3, #8                  \n"  // 8 src pixels per loop
       "ld1         {v1.8h}, [%1], #16            \n"  // load 8 V
+      "subs        %w3, %w3, #8                  \n"  // 8 src pixels per loop
       "ushl        v0.8h, v0.8h, v2.8h           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "ushl        v1.8h, v1.8h, v2.8h           \n"
@@ -843,7 +1332,7 @@
                      uint8_t* dst_uv,
                      int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load U
       "ld1         {v1.16b}, [%1], #16           \n"  // load V
       "subs        %w3, %w3, #16                 \n"  // 16 processed per loop
@@ -870,10 +1359,10 @@
   int shift = 16 - depth;
   asm volatile(
       "dup         v4.8h, %w4                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%0], #16            \n"  // load 8 U
-      "subs        %w3, %w3, #8                  \n"  // 8 src pixels per loop
       "ld1         {v1.8h}, [%1], #16            \n"  // load 8 V
+      "subs        %w3, %w3, #8                  \n"  // 8 src pixels per loop
       "ushl        v0.8h, v0.8h, v4.8h           \n"
       "ushl        v1.8h, v1.8h, v4.8h           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -898,7 +1387,7 @@
                       uint8_t* dst_b,
                       int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.16b,v1.16b,v2.16b}, [%0], #48 \n"  // load 16 RGB
       "subs        %w4, %w4, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -923,7 +1412,7 @@
                       uint8_t* dst_rgb,
                       int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load R
       "ld1         {v1.16b}, [%1], #16           \n"  // load G
       "ld1         {v2.16b}, [%2], #16           \n"  // load B
@@ -951,7 +1440,7 @@
                        uint8_t* dst_a,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ARGB
       "subs        %w5, %w5, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -971,7 +1460,7 @@
   );
 }
 
-#if LIBYUV_USE_ST4
+#if defined(LIBYUV_USE_ST4)
 // Reads 16 planar R's, G's, B's and A's and writes out 16 packed ARGB at a time
 void MergeARGBRow_NEON(const uint8_t* src_r,
                        const uint8_t* src_g,
@@ -980,7 +1469,7 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%2], #16           \n"  // load B
       "ld1         {v1.16b}, [%1], #16           \n"  // load G
       "ld1         {v2.16b}, [%0], #16           \n"  // load R
@@ -1011,7 +1500,7 @@
                        uint8_t* dst_argb,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%2], #16           \n"  // load B
       "ld1         {v1.16b}, [%1], #16           \n"  // load G
       "ld1         {v2.16b}, [%0], #16           \n"  // load R
@@ -1051,7 +1540,7 @@
                        uint8_t* dst_b,
                        int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ARGB
       "subs        %w4, %w4, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1077,7 +1566,7 @@
                        int width) {
   asm volatile(
       "movi        v3.16b, #255                  \n"  // load A(255)
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v2.16b}, [%0], #16           \n"  // load R
       "ld1         {v1.16b}, [%1], #16           \n"  // load G
       "ld1         {v0.16b}, [%2], #16           \n"  // load B
@@ -1108,10 +1597,11 @@
       "movi        v30.16b, #255                 \n"
       "ushr        v30.4s, v30.4s, #22           \n"  // 1023
       "dup         v31.4s, %w5                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d2, [%2], #8                  \n"  // B
       "ldr         d1, [%1], #8                  \n"  // G
       "ldr         d0, [%0], #8                  \n"  // R
+      "subs        %w4, %w4, #4                  \n"
       "ushll       v2.4s, v2.4h, #0              \n"  // B
       "ushll       v1.4s, v1.4h, #0              \n"  // G
       "ushll       v0.4s, v0.4h, #0              \n"  // R
@@ -1124,7 +1614,6 @@
       "sli         v2.4s, v1.4s, #10             \n"  // 00GB
       "sli         v2.4s, v0.4s, #20             \n"  // 0RGB
       "orr         v2.4s, #0xc0, lsl #24         \n"  // ARGB (AR30)
-      "subs        %w4, %w4, #4                  \n"
       "str         q2, [%3], #16                 \n"
       "b.gt        1b                            \n"
       : "+r"(src_r),     // %0
@@ -1142,32 +1631,34 @@
                           uint8_t* dst_ar30,
                           int /* depth */,
                           int width) {
+  // Neon has no "shift left and accumulate/orr", so use a multiply-add to
+  // perform the shift instead.
+  int limit = 1023;
   asm volatile(
-      "movi        v30.16b, #255                 \n"
-      "ushr        v30.4s, v30.4s, #22           \n"  // 1023
-      "1:                                        \n"
-      "ldr         d2, [%2], #8                  \n"  // B
-      "ldr         d1, [%1], #8                  \n"  // G
-      "ldr         d0, [%0], #8                  \n"  // R
-      "ushll       v2.4s, v2.4h, #0              \n"  // 000B
-      "ushll       v1.4s, v1.4h, #0              \n"  // G
-      "ushll       v0.4s, v0.4h, #0              \n"  // R
-      "umin        v2.4s, v2.4s, v30.4s          \n"
-      "umin        v1.4s, v1.4s, v30.4s          \n"
-      "umin        v0.4s, v0.4s, v30.4s          \n"
-      "sli         v2.4s, v1.4s, #10             \n"  // 00GB
-      "sli         v2.4s, v0.4s, #20             \n"  // 0RGB
-      "orr         v2.4s, #0xc0, lsl #24         \n"  // ARGB (AR30)
-      "subs        %w4, %w4, #4                  \n"
-      "str         q2, [%3], #16                 \n"
+      "dup         v5.8h, %w[limit]              \n"
+      "movi        v6.8h, #16                    \n"  // 1 << 4
+      "movi        v7.8h, #4, lsl #8             \n"  // 1 << 10
+      "1:          \n"
+      "ldr         q0, [%0], #16                 \n"  // xxxxxxRrrrrrrrrr
+      "ldr         q1, [%1], #16                 \n"  // xxxxxxGggggggggg
+      "ldr         q2, [%2], #16                 \n"  // xxxxxxBbbbbbbbbb
+      "subs        %w4, %w4, #8                  \n"
+      "umin        v0.8h, v0.8h, v5.8h           \n"  // 000000Rrrrrrrrrr
+      "umin        v1.8h, v1.8h, v5.8h           \n"  // 000000Gggggggggg
+      "movi        v4.8h, #0xc0, lsl #8          \n"  // 1100000000000000
+      "umin        v3.8h, v2.8h, v5.8h           \n"  // 000000Bbbbbbbbbb
+      "mla         v4.8h, v0.8h, v6.8h           \n"  // 11Rrrrrrrrrr0000
+      "mla         v3.8h, v1.8h, v7.8h           \n"  // ggggggBbbbbbbbbb
+      "usra        v4.8h, v1.8h, #6              \n"  // 11RrrrrrrrrrGggg
+      "st2         {v3.8h, v4.8h}, [%3], #32     \n"
       "b.gt        1b                            \n"
       : "+r"(src_r),     // %0
         "+r"(src_g),     // %1
         "+r"(src_b),     // %2
         "+r"(dst_ar30),  // %3
         "+r"(width)      // %4
-      :
-      : "memory", "cc", "v0", "v1", "v2", "v30");
+      : [limit] "r"(limit)
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
 }
 
 void MergeAR64Row_NEON(const uint16_t* src_r,
@@ -1183,11 +1674,12 @@
 
       "dup         v30.8h, %w7                   \n"
       "dup         v31.8h, %w6                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q2, [%0], #16                 \n"  // R
       "ldr         q1, [%1], #16                 \n"  // G
       "ldr         q0, [%2], #16                 \n"  // B
       "ldr         q3, [%3], #16                 \n"  // A
+      "subs        %w5, %w5, #8                  \n"
       "umin        v2.8h, v2.8h, v30.8h          \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "umin        v1.8h, v1.8h, v30.8h          \n"
@@ -1200,7 +1692,6 @@
       "ushl        v1.8h, v1.8h, v31.8h          \n"
       "ushl        v0.8h, v0.8h, v31.8h          \n"
       "ushl        v3.8h, v3.8h, v31.8h          \n"
-      "subs        %w5, %w5, #8                  \n"
       "st4         {v0.8h, v1.8h, v2.8h, v3.8h}, [%4], #64 \n"
       "b.gt        1b                            \n"
       : "+r"(src_r),     // %0
@@ -1228,10 +1719,11 @@
       "dup         v30.8h, %w6                   \n"
       "dup         v31.8h, %w5                   \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q2, [%0], #16                 \n"  // R
       "ldr         q1, [%1], #16                 \n"  // G
       "ldr         q0, [%2], #16                 \n"  // B
+      "subs        %w4, %w4, #8                  \n"
       "umin        v2.8h, v2.8h, v30.8h          \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "umin        v1.8h, v1.8h, v30.8h          \n"
@@ -1241,7 +1733,6 @@
       "ushl        v2.8h, v2.8h, v31.8h          \n"
       "ushl        v1.8h, v1.8h, v31.8h          \n"
       "ushl        v0.8h, v0.8h, v31.8h          \n"
-      "subs        %w4, %w4, #8                  \n"
       "st4         {v0.8h, v1.8h, v2.8h, v3.8h}, [%3], #64 \n"
       "b.gt        1b                            \n"
       : "+r"(src_r),     // %0
@@ -1261,33 +1752,31 @@
                             uint8_t* dst_argb,
                             int depth,
                             int width) {
-  int shift = 8 - depth;
+  // Shift is 8 - depth, +8 so the result is in the top half of each lane.
+  int shift = 16 - depth;
   asm volatile(
-
       "dup         v31.8h, %w6                   \n"
-      "1:                                        \n"
-      "ldr         q2, [%0], #16                 \n"  // R
+      "1:          \n"
+      "ldr         q0, [%0], #16                 \n"  // B
       "ldr         q1, [%1], #16                 \n"  // G
-      "ldr         q0, [%2], #16                 \n"  // B
+      "ldr         q2, [%2], #16                 \n"  // R
       "ldr         q3, [%3], #16                 \n"  // A
-      "ushl        v2.8h, v2.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "ushl        v1.8h, v1.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "ushl        v0.8h, v0.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%2, 448]          \n"
-      "ushl        v3.8h, v3.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%3, 448]          \n"
-      "uqxtn       v2.8b, v2.8h                  \n"
-      "uqxtn       v1.8b, v1.8h                  \n"
-      "uqxtn       v0.8b, v0.8h                  \n"
-      "uqxtn       v3.8b, v3.8h                  \n"
       "subs        %w5, %w5, #8                  \n"
-      "st4         {v0.8b, v1.8b, v2.8b, v3.8b}, [%4], #32 \n"
+      "uqshl       v0.8h, v0.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uqshl       v1.8h, v1.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "uqshl       v2.8h, v2.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%2, 448]          \n"
+      "uqshl       v3.8h, v3.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%3, 448]          \n"
+      "trn2        v0.16b, v0.16b, v1.16b        \n"
+      "trn2        v1.16b, v2.16b, v3.16b        \n"
+      "st2         {v0.8h, v1.8h}, [%4], #32     \n"
       "b.gt        1b                            \n"
-      : "+r"(src_r),     // %0
+      : "+r"(src_b),     // %0
         "+r"(src_g),     // %1
-        "+r"(src_b),     // %2
+        "+r"(src_r),     // %2
         "+r"(src_a),     // %3
         "+r"(dst_argb),  // %4
         "+r"(width)      // %5
@@ -1301,30 +1790,29 @@
                             uint8_t* dst_argb,
                             int depth,
                             int width) {
-  int shift = 8 - depth;
+  // Shift is 8 - depth, +8 so the result is in the top half of each lane.
+  int shift = 16 - depth;
   asm volatile(
-
       "dup         v31.8h, %w5                   \n"
-      "movi        v3.8b, #0xff                  \n"  // A (0xff)
-      "1:                                        \n"
-      "ldr         q2, [%0], #16                 \n"  // R
+      "movi        v3.16b, #0xff                 \n"  // A (0xff)
+      "1:          \n"
+      "ldr         q0, [%0], #16                 \n"  // B
       "ldr         q1, [%1], #16                 \n"  // G
-      "ldr         q0, [%2], #16                 \n"  // B
-      "ushl        v2.8h, v2.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "ushl        v1.8h, v1.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "ushl        v0.8h, v0.8h, v31.8h          \n"
-      "prfm        pldl1keep, [%2, 448]          \n"
-      "uqxtn       v2.8b, v2.8h                  \n"
-      "uqxtn       v1.8b, v1.8h                  \n"
-      "uqxtn       v0.8b, v0.8h                  \n"
+      "ldr         q2, [%2], #16                 \n"  // R
       "subs        %w4, %w4, #8                  \n"
-      "st4         {v0.8b, v1.8b, v2.8b, v3.8b}, [%3], #32 \n"
+      "uqshl       v0.8h, v0.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uqshl       v1.8h, v1.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "uqshl       v2.8h, v2.8h, v31.8h          \n"
+      "prfm        pldl1keep, [%2, 448]          \n"
+      "trn2        v0.16b, v0.16b, v1.16b        \n"
+      "trn2        v1.16b, v2.16b, v3.16b        \n"
+      "st2         {v0.8h, v1.8h}, [%3], #32     \n"
       "b.gt        1b                            \n"
-      : "+r"(src_r),     // %0
+      : "+r"(src_b),     // %0
         "+r"(src_g),     // %1
-        "+r"(src_b),     // %2
+        "+r"(src_r),     // %2
         "+r"(dst_argb),  // %3
         "+r"(width)      // %4
       : "r"(shift)       // %5
@@ -1334,7 +1822,7 @@
 // Copy multiple of 32.
 void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "subs        %w2, %w2, #32                 \n"  // 32 processed per loop
@@ -1352,7 +1840,7 @@
 void SetRow_NEON(uint8_t* dst, uint8_t v8, int width) {
   asm volatile(
       "dup         v0.16b, %w2                   \n"  // duplicate 16 bytes
-      "1:                                        \n"
+      "1:          \n"
       "subs        %w1, %w1, #16                 \n"  // 16 bytes per loop
       "st1         {v0.16b}, [%0], #16           \n"  // store
       "b.gt        1b                            \n"
@@ -1365,7 +1853,7 @@
 void ARGBSetRow_NEON(uint8_t* dst, uint32_t v32, int width) {
   asm volatile(
       "dup         v0.4s, %w2                    \n"  // duplicate 4 ints
-      "1:                                        \n"
+      "1:          \n"
       "subs        %w1, %w1, #4                  \n"  // 4 ints per loop
       "st1         {v0.16b}, [%0], #16           \n"  // store
       "b.gt        1b                            \n"
@@ -1385,7 +1873,7 @@
       "ld1         {v3.16b}, [%3]                \n"  // shuffler
       "add         %0, %0, %w2, sxtw             \n"
       "sub         %0, %0, #32                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q2, [%0, 16]                  \n"
       "ldr         q1, [%0], -32                 \n"  // src -= 32
       "subs        %w2, %w2, #32                 \n"  // 32 pixels per loop.
@@ -1410,7 +1898,7 @@
       "ld1         {v4.16b}, [%3]                \n"  // shuffler
       "add         %0, %0, %w2, sxtw #1          \n"
       "sub         %0, %0, #32                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q1, [%0, 16]                  \n"
       "ldr         q0, [%0], -32                 \n"  // src -= 32
       "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop.
@@ -1434,7 +1922,7 @@
       "ld1         {v4.16b}, [%4]                \n"  // shuffler
       "add         %0, %0, %w3, sxtw #1          \n"
       "sub         %0, %0, #32                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q1, [%0, 16]                  \n"
       "ldr         q0, [%0], -32                 \n"  // src -= 32
       "subs        %w3, %w3, #16                 \n"  // 16 pixels per loop.
@@ -1463,7 +1951,7 @@
       "ld1         {v4.16b}, [%3]                \n"  // shuffler
       "add         %0, %0, %w2, sxtw #2          \n"
       "sub         %0, %0, #32                   \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldr         q1, [%0, 16]                  \n"
       "ldr         q0, [%0], -32                 \n"  // src -= 32
       "subs        %w2, %w2, #8                  \n"  // 8 pixels per loop.
@@ -1487,7 +1975,7 @@
       "add         %0, %0, %w2, sxtw             \n"
       "sub         %0, %0, #48                   \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.16b, v1.16b, v2.16b}, [%0], %3 \n"  // src -= 48
       "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop.
       "tbl         v0.16b, {v0.16b}, v3.16b      \n"
@@ -1508,11 +1996,11 @@
                          int width) {
   asm volatile(
       "movi        v4.8b, #255                   \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v1.8b,v2.8b,v3.8b}, [%0], #24 \n"  // load 8 pixels of
                                                        // RGB24.
+      "subs        %w2, %w2, #8                  \n"   // 8 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "st4         {v1.8b,v2.8b,v3.8b,v4.8b}, [%1], #32 \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_rgb24),  // %0
@@ -1526,12 +2014,12 @@
 void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
   asm volatile(
       "movi        v5.8b, #255                   \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.8b,v1.8b,v2.8b}, [%0], #24 \n"  // read r g b
       "subs        %w2, %w2, #8                  \n"   // 8 processed per loop.
-      "orr         v3.8b, v1.8b, v1.8b           \n"   // move g
+      "mov         v3.8b, v1.8b                  \n"   // move g
       "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v4.8b, v0.8b, v0.8b           \n"         // move r
+      "mov         v4.8b, v0.8b                  \n"         // move r
       "st4         {v2.8b,v3.8b,v4.8b,v5.8b}, [%1], #32 \n"  // store b g r a
       "b.gt        1b                            \n"
       : "+r"(src_raw),   // %0
@@ -1545,12 +2033,12 @@
 void RAWToRGBARow_NEON(const uint8_t* src_raw, uint8_t* dst_rgba, int width) {
   asm volatile(
       "movi        v0.8b, #255                   \n"  // Alpha
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v3.8b,v4.8b,v5.8b}, [%0], #24 \n"  // read r g b
       "subs        %w2, %w2, #8                  \n"   // 8 processed per loop.
-      "orr         v2.8b, v4.8b, v4.8b           \n"   // move g
+      "mov         v2.8b, v4.8b                  \n"   // move g
       "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v1.8b, v5.8b, v5.8b           \n"         // move r
+      "mov         v1.8b, v5.8b                  \n"         // move r
       "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%1], #32 \n"  // store a b g r
       "b.gt        1b                            \n"
       : "+r"(src_raw),   // %0
@@ -1563,12 +2051,12 @@
 
 void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.8b,v1.8b,v2.8b}, [%0], #24 \n"  // read r g b
       "subs        %w2, %w2, #8                  \n"   // 8 processed per loop.
-      "orr         v3.8b, v1.8b, v1.8b           \n"   // move g
+      "mov         v3.8b, v1.8b                  \n"   // move g
       "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v4.8b, v0.8b, v0.8b           \n"   // move r
+      "mov         v4.8b, v0.8b                  \n"   // move r
       "st3         {v2.8b,v3.8b,v4.8b}, [%1], #24 \n"  // store b g r
       "b.gt        1b                            \n"
       : "+r"(src_raw),    // %0
@@ -1579,29 +2067,28 @@
   );
 }
 
-#define RGB565TOARGB                                                        \
-  "shrn       v6.8b, v0.8h, #5               \n" /* G xxGGGGGG           */ \
-  "shl        v6.8b, v6.8b, #2               \n" /* G GGGGGG00 upper 6   */ \
-  "ushr       v4.8b, v6.8b, #6               \n" /* G 000000GG lower 2   */ \
-  "orr        v1.8b, v4.8b, v6.8b            \n" /* G                    */ \
-  "xtn        v2.8b, v0.8h                   \n" /* B xxxBBBBB           */ \
-  "ushr       v0.8h, v0.8h, #11              \n" /* R 000RRRRR           */ \
-  "xtn2       v2.16b,v0.8h                   \n" /* R in upper part      */ \
-  "shl        v2.16b, v2.16b, #3             \n" /* R,B BBBBB000 upper 5 */ \
-  "ushr       v0.16b, v2.16b, #5             \n" /* R,B 00000BBB lower 3 */ \
-  "orr        v0.16b, v0.16b, v2.16b         \n" /* R,B                  */ \
-  "dup        v2.2D, v0.D[1]                 \n" /* R                    */
+#define RGB565TOARGB                                                      \
+  /* Input: v0/v4.8h: RRRRRGGGGGGBBBBB */                                 \
+  "shrn       v1.8b, v0.8h, #3               \n" /* G GGGGGGxx */         \
+  "shrn2      v1.16b, v4.8h, #3              \n" /* G GGGGGGxx */         \
+  "uzp2       v2.16b, v0.16b, v4.16b         \n" /* R RRRRRxxx */         \
+  "uzp1       v0.16b, v0.16b, v4.16b         \n" /* B xxxBBBBB */         \
+  "sri        v1.16b, v1.16b, #6             \n" /* G GGGGGGGG, fill 2 */ \
+  "shl        v0.16b, v0.16b, #3             \n" /* B BBBBB000 */         \
+  "sri        v2.16b, v2.16b, #5             \n" /* R RRRRRRRR, fill 3 */ \
+  "sri        v0.16b, v0.16b, #5             \n" /* R BBBBBBBB, fill 3 */
 
 void RGB565ToARGBRow_NEON(const uint8_t* src_rgb565,
                           uint8_t* dst_argb,
                           int width) {
   asm volatile(
-      "movi        v3.8b, #255                   \n"  // Alpha
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 RGB565 pixels.
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
+      "movi        v3.16b, #255                  \n"  // Alpha
+      "1:          \n"
+      "ldp         q0, q4, [%0], #32             \n"  // load 16 RGB565 pixels
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n" RGB565TOARGB
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%1], #32 \n"  // store 8 ARGB
+      "st4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%1] \n"  // store 16 ARGB
+      "add         %1, %1, #64                   \n"
       "b.gt        1b                            \n"
       : "+r"(src_rgb565),  // %0
         "+r"(dst_argb),    // %1
@@ -1611,86 +2098,79 @@
   );
 }
 
-#define ARGB1555TOARGB                                                      \
-  "ushr       v2.8h, v0.8h, #10              \n" /* R xxxRRRRR           */ \
-  "shl        v2.8h, v2.8h, #3               \n" /* R RRRRR000 upper 5   */ \
-  "xtn        v3.8b, v2.8h                   \n" /* RRRRR000 AAAAAAAA    */ \
-                                                                            \
-  "sshr       v2.8h, v0.8h, #15              \n" /* A AAAAAAAA           */ \
-  "xtn2       v3.16b, v2.8h                  \n"                            \
-                                                                            \
-  "xtn        v2.8b, v0.8h                   \n" /* B xxxBBBBB           */ \
-  "shrn2      v2.16b,v0.8h, #5               \n" /* G xxxGGGGG           */ \
-                                                                            \
-  "ushr       v1.16b, v3.16b, #5             \n" /* R,A 00000RRR lower 3 */ \
-  "shl        v0.16b, v2.16b, #3             \n" /* B,G BBBBB000 upper 5 */ \
-  "ushr       v2.16b, v0.16b, #5             \n" /* B,G 00000BBB lower 3 */ \
-                                                                            \
-  "orr        v0.16b, v0.16b, v2.16b         \n" /* B,G                  */ \
-  "orr        v2.16b, v1.16b, v3.16b         \n" /* R,A                  */ \
-  "dup        v1.2D, v0.D[1]                 \n"                            \
-  "dup        v3.2D, v2.D[1]                 \n"
+#define ARGB1555TOARGB                                   \
+  /* Input: ARRRRRGGGGGBBBBB */                          \
+  "shrn       v2.8b, v0.8h, #7        \n" /* RRRRRxxx */ \
+  "uzp1       v29.16b, v0.16b, v4.16b \n" /* xxxBBBBB */ \
+  "shrn       v1.8b, v0.8h, #2        \n" /* GGGGGxxx */ \
+  "uzp2       v3.16b, v0.16b, v4.16b  \n" /* Axxxxxxx */ \
+  "shrn2      v2.16b, v4.8h, #7       \n" /* RRRRRxxx */ \
+  "shl        v0.16b, v29.16b, #3     \n" /* BBBBB000 */ \
+  "shrn2      v1.16b, v4.8h, #2       \n" /* GGGGGxxx */ \
+  "sshr       v3.16b, v3.16b, #7      \n" /* AAAAAAAA */ \
+  "sri        v2.16b, v2.16b, #5      \n" /* RRRRRRRR */ \
+  "sri        v1.16b, v1.16b, #5      \n" /* GGGGGGGG */ \
+  "sri        v0.16b, v0.16b, #5      \n" /* BBBBBBBB */
 
 // RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha.
-#define RGB555TOARGB                                                        \
-  "ushr       v2.8h, v0.8h, #10              \n" /* R xxxRRRRR           */ \
-  "shl        v2.8h, v2.8h, #3               \n" /* R RRRRR000 upper 5   */ \
-  "xtn        v3.8b, v2.8h                   \n" /* RRRRR000             */ \
-                                                                            \
-  "xtn        v2.8b, v0.8h                   \n" /* B xxxBBBBB           */ \
-  "shrn2      v2.16b,v0.8h, #5               \n" /* G xxxGGGGG           */ \
-                                                                            \
-  "ushr       v1.16b, v3.16b, #5             \n" /* R   00000RRR lower 3 */ \
-  "shl        v0.16b, v2.16b, #3             \n" /* B,G BBBBB000 upper 5 */ \
-  "ushr       v2.16b, v0.16b, #5             \n" /* B,G 00000BBB lower 3 */ \
-                                                                            \
-  "orr        v0.16b, v0.16b, v2.16b         \n" /* B,G                  */ \
-  "orr        v2.16b, v1.16b, v3.16b         \n" /* R                    */ \
-  "dup        v1.2D, v0.D[1]                 \n" /* G */
+#define RGB555TOARGB                                         \
+  /* Input: xRRRRRGGGGGBBBBB */                              \
+  "uzp1       v29.16b, v0.16b, v3.16b     \n" /* xxxBBBBB */ \
+  "shrn       v2.8b, v0.8h, #7            \n" /* RRRRRxxx */ \
+  "shrn       v1.8b, v0.8h, #2            \n" /* GGGGGxxx */ \
+  "shl        v0.16b, v29.16b, #3         \n" /* BBBBB000 */ \
+  "shrn2      v2.16b, v3.8h, #7           \n" /* RRRRRxxx */ \
+  "shrn2      v1.16b, v3.8h, #2           \n" /* GGGGGxxx */ \
+                                                             \
+  "sri        v0.16b, v0.16b, #5          \n" /* BBBBBBBB */ \
+  "sri        v2.16b, v2.16b, #5          \n" /* RRRRRRRR */ \
+  "sri        v1.16b, v1.16b, #5          \n" /* GGGGGGGG */
 
 void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555,
                             uint8_t* dst_argb,
                             int width) {
   asm volatile(
-      "movi        v3.8b, #255                   \n"  // Alpha
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB1555 pixels.
+      "1:          \n"
+      "ldp         q0, q4, [%0], #32             \n"  // load 16 ARGB1555 pixels
       "prfm        pldl1keep, [%0, 448]          \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
       ARGB1555TOARGB
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%1], #32 \n"  // store 8 ARGB
+      "st4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%1] \n"  // store 16 ARGB
+      "add         %1, %1, #64                   \n"
       "b.gt        1b                            \n"
       : "+r"(src_argb1555),  // %0
         "+r"(dst_argb),      // %1
         "+r"(width)          // %2
       :
-      : "cc", "memory", "v0", "v1", "v2", "v3"  // Clobber List
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v29"  // Clobber List
   );
 }
 
-// Convert v0.8h to b = v0.8b g = v1.8b r = v2.8b
-// clobbers v3
-#define ARGB4444TOARGB                                                      \
-  "shrn       v1.8b,  v0.8h, #8              \n" /* v1(l) AR             */ \
-  "xtn2       v1.16b, v0.8h                  \n" /* v1(h) GB             */ \
-  "shl        v2.16b, v1.16b, #4             \n" /* B,R BBBB0000         */ \
-  "ushr       v3.16b, v1.16b, #4             \n" /* G,A 0000GGGG         */ \
-  "ushr       v0.16b, v2.16b, #4             \n" /* B,R 0000BBBB         */ \
-  "shl        v1.16b, v3.16b, #4             \n" /* G,A GGGG0000         */ \
-  "orr        v2.16b, v0.16b, v2.16b         \n" /* B,R BBBBBBBB         */ \
-  "orr        v3.16b, v1.16b, v3.16b         \n" /* G,A GGGGGGGG         */ \
-  "dup        v0.2D, v2.D[1]                 \n"                            \
-  "dup        v1.2D, v3.D[1]                 \n"
+#define ARGB4444TOARGB                                        \
+  /* Input: v1.8h = AAAARRRR_GGGGBBBB */                      \
+  "shl        v0.16b, v1.16b, #4  \n" /* RRRR0000_BBBB0000 */ \
+  "sri        v1.16b, v1.16b, #4  \n" /* AAAAAAAA_GGGGGGGG */ \
+  "sri        v0.16b, v0.16b, #4  \n" /* RRRRRRRR_BBBBBBBB */
+
+#define ARGB4444TORGB                                    \
+  /* Input: v0.8h = xxxxRRRRGGGGBBBB */                  \
+  "uzp1       v1.16b, v0.16b, v3.16b  \n" /* GGGGBBBB */ \
+  "shrn       v2.8b, v0.8h, #4        \n" /* RRRRxxxx */ \
+  "shl        v0.16b, v1.16b, #4      \n" /* BBBB0000 */ \
+  "shrn2      v2.16b, v3.8h, #4       \n" /* RRRRxxxx */ \
+  "sri        v1.16b, v1.16b, #4      \n" /* GGGGGGGG */ \
+  "sri        v2.16b, v2.16b, #4      \n" /* RRRRRRRR */ \
+  "sri        v0.16b, v0.16b, #4      \n" /* BBBBBBBB */
 
 void ARGB4444ToARGBRow_NEON(const uint8_t* src_argb4444,
                             uint8_t* dst_argb,
                             int width) {
   asm volatile(
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB4444 pixels.
+      "1:          \n"
+      "ld1         {v1.16b}, [%0], #16           \n"  // load 8 ARGB4444 pixels.
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n" ARGB4444TOARGB
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%1], #32 \n"  // store 8 ARGB
+      "st2         {v0.16b, v1.16b}, [%1], #32   \n"  // store 8 ARGB.
       "b.gt        1b                            \n"
       : "+r"(src_argb4444),  // %0
         "+r"(dst_argb),      // %1
@@ -1700,11 +2180,64 @@
   );
 }
 
+static const int16_t kAR30Row_BoxShifts[] = {0, -6, 0, -6, 0, -6, 0, -6};
+
+static const uint8_t kABGRToAR30Row_BoxIndices[] = {
+    2, 2, 1, 1, 6, 6, 5, 5, 10, 10, 9,  9,  14, 14, 13, 13,
+    0, 0, 3, 3, 4, 4, 7, 7, 8,  8,  11, 11, 12, 12, 15, 15};
+static const uint8_t kARGBToAR30Row_BoxIndices[] = {
+    0, 0, 1, 1, 4, 4, 5, 5, 8,  8,  9,  9,  12, 12, 13, 13,
+    2, 2, 3, 3, 6, 6, 7, 7, 10, 10, 11, 11, 14, 14, 15, 15};
+
+// ARGB or ABGR as input, reordering based on TBL indices parameter.
+static void ABCDToAR30Row_NEON(const uint8_t* src_abcd,
+                               uint8_t* dst_ar30,
+                               int width,
+                               const uint8_t* indices) {
+  asm volatile(
+      "movi        v2.4s, #0xf, msl 16           \n"  // 0xfffff
+      "ldr         q3, [%[kAR30Row_BoxShifts]]   \n"
+      "ldp         q4, q5, [%[indices]]          \n"
+      "1:          \n"
+      "ldp         q0, q20, [%[src]], #32        \n"
+      "subs        %w[width], %w[width], #8      \n"
+      "tbl         v1.16b, {v0.16b}, v5.16b      \n"
+      "tbl         v21.16b, {v20.16b}, v5.16b    \n"
+      "tbl         v0.16b, {v0.16b}, v4.16b      \n"
+      "tbl         v20.16b, {v20.16b}, v4.16b    \n"
+      "ushl        v0.8h, v0.8h, v3.8h           \n"
+      "ushl        v20.8h, v20.8h, v3.8h         \n"
+      "ushl        v1.8h, v1.8h, v3.8h           \n"
+      "ushl        v21.8h, v21.8h, v3.8h         \n"
+      "ushr        v0.4s, v0.4s, #6              \n"
+      "ushr        v20.4s, v20.4s, #6            \n"
+      "shl         v1.4s, v1.4s, #14             \n"
+      "shl         v21.4s, v21.4s, #14           \n"
+      "bif         v0.16b, v1.16b, v2.16b        \n"
+      "bif         v20.16b, v21.16b, v2.16b      \n"
+      "stp         q0, q20, [%[dst]], #32        \n"
+      "b.gt        1b                            \n"
+      : [src] "+r"(src_abcd),                          // %[src]
+        [dst] "+r"(dst_ar30),                          // %[dst]
+        [width] "+r"(width)                            // %[width]
+      : [kAR30Row_BoxShifts] "r"(kAR30Row_BoxShifts),  // %[kAR30Row_BoxShifts]
+        [indices] "r"(indices)                         // %[indices]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v20", "v21");
+}
+
+void ABGRToAR30Row_NEON(const uint8_t* src_abgr, uint8_t* dst_ar30, int width) {
+  ABCDToAR30Row_NEON(src_abgr, dst_ar30, width, kABGRToAR30Row_BoxIndices);
+}
+
+void ARGBToAR30Row_NEON(const uint8_t* src_argb, uint8_t* dst_ar30, int width) {
+  ABCDToAR30Row_NEON(src_argb, dst_ar30, width, kARGBToAR30Row_BoxIndices);
+}
+
 void ARGBToRGB24Row_NEON(const uint8_t* src_argb,
                          uint8_t* dst_rgb24,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ARGB
       "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop.
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1720,12 +2253,12 @@
 
 void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v1.8b,v2.8b,v3.8b,v4.8b}, [%0], #32 \n"  // load b g r a
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
-      "orr         v4.8b, v2.8b, v2.8b           \n"  // mov g
+      "mov         v4.8b, v2.8b                  \n"  // mov g
       "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v5.8b, v1.8b, v1.8b           \n"   // mov b
+      "mov         v5.8b, v1.8b                  \n"   // mov b
       "st3         {v3.8b,v4.8b,v5.8b}, [%1], #24 \n"  // store r g b
       "b.gt        1b                            \n"
       : "+r"(src_argb),  // %0
@@ -1738,7 +2271,7 @@
 
 void YUY2ToYRow_NEON(const uint8_t* src_yuy2, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"  // load 16 pixels of YUY2.
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1754,7 +2287,7 @@
 
 void UYVYToYRow_NEON(const uint8_t* src_uyvy, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"  // load 16 pixels of UYVY.
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1773,7 +2306,7 @@
                          uint8_t* dst_v,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 16 YUY2
       "subs        %w3, %w3, #16                 \n"  // 16 pixels = 8 UVs.
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1794,7 +2327,7 @@
                          uint8_t* dst_v,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 16 UYVY
       "subs        %w3, %w3, #16                 \n"  // 16 pixels = 8 UVs.
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1817,7 +2350,7 @@
                       int width) {
   const uint8_t* src_yuy2b = src_yuy2 + stride_yuy2;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 16 pixels
       "subs        %w4, %w4, #16                 \n"  // 16 pixels = 8 UVs.
       "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load next row
@@ -1845,7 +2378,7 @@
                       int width) {
   const uint8_t* src_uyvyb = src_uyvy + stride_uyvy;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 16 pixels
       "subs        %w4, %w4, #16                 \n"  // 16 pixels = 8 UVs.
       "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load next row
@@ -1872,7 +2405,7 @@
                         int width) {
   const uint8_t* src_yuy2b = src_yuy2 + stride_yuy2;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"  // load 16 pixels
       "subs        %w3, %w3, #16                 \n"  // 16 pixels = 8 UVs.
       "ld2         {v2.16b,v3.16b}, [%1], #32    \n"  // load next row
@@ -1896,7 +2429,7 @@
                          int width) {
   asm volatile(
       "ld1         {v2.16b}, [%3]                \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load 4 pixels.
       "subs        %w2, %w2, #4                  \n"  // 4 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -1917,10 +2450,10 @@
                         uint8_t* dst_yuy2,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.8b, v1.8b}, [%0], #16     \n"  // load 16 Ys
       "subs        %w4, %w4, #16                 \n"  // 16 pixels
-      "orr         v2.8b, v1.8b, v1.8b           \n"
+      "mov         v2.8b, v1.8b                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "ld1         {v1.8b}, [%1], #8             \n"         // load 8 Us
       "ld1         {v3.8b}, [%2], #8             \n"         // load 8 Vs
@@ -1941,13 +2474,13 @@
                         uint8_t* dst_uyvy,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v1.8b,v2.8b}, [%0], #16      \n"  // load 16 Ys
-      "orr         v3.8b, v2.8b, v2.8b           \n"
+      "subs        %w4, %w4, #16                 \n"  // 16 pixels
+      "mov         v3.8b, v2.8b                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "ld1         {v0.8b}, [%1], #8             \n"         // load 8 Us
       "ld1         {v2.8b}, [%2], #8             \n"         // load 8 Vs
-      "subs        %w4, %w4, #16                 \n"         // 16 pixels
       "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%3], #32 \n"  // Store 16 pixels.
       "b.gt        1b                            \n"
       : "+r"(src_y),     // %0
@@ -1963,7 +2496,7 @@
                           uint8_t* dst_rgb565,
                           int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%0], #32 \n"  // load 8
                                                                  // pixels
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
@@ -1983,7 +2516,7 @@
                                 int width) {
   asm volatile(
       "dup         v1.4s, %w3                    \n"  // dither4
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "uqadd       v16.8b, v16.8b, v1.8b         \n"
@@ -2003,27 +2536,24 @@
                             uint8_t* dst_argb1555,
                             int width) {
   asm volatile(
-      "1:                                        \n"
-      "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%0], #32 \n"  // load 8
-                                                                 // pixels
+      "1:          \n"
+      "ld2         {v16.8h,v17.8h}, [%0], #32    \n"  // load 8 pixels
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n" ARGBTOARGB1555
-      "st1         {v0.16b}, [%1], #16           \n"  // store 8 pixels
+      "st1         {v17.16b}, [%1], #16          \n"  // store 8 pixels
       "b.gt        1b                            \n"
       : "+r"(src_argb),      // %0
         "+r"(dst_argb1555),  // %1
         "+r"(width)          // %2
       :
-      : "cc", "memory", "v0", "v16", "v17", "v18", "v19");
+      : "cc", "memory", "v1", "v2", "v16", "v17");
 }
 
 void ARGBToARGB4444Row_NEON(const uint8_t* src_argb,
                             uint8_t* dst_argb4444,
                             int width) {
   asm volatile(
-      "movi        v23.16b, #0x0f                \n"  // bits to clear with
-                                                      // vbic.
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%0], #32 \n"  // load 8
                                                                  // pixels
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
@@ -2034,20 +2564,20 @@
         "+r"(dst_argb4444),  // %1
         "+r"(width)          // %2
       :
-      : "cc", "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v23");
+      : "cc", "memory", "v0", "v1", "v16", "v17", "v18", "v19");
 }
 
-#if LIBYUV_USE_ST2
+#if defined(LIBYUV_USE_ST2)
 void ARGBToAR64Row_NEON(const uint8_t* src_argb,
                         uint16_t* dst_ar64,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q2, [%0], #32             \n"  // load 8 pixels
+      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "mov         v1.16b, v0.16b                \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "mov         v3.16b, v2.16b                \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "st2         {v0.16b, v1.16b}, [%1], #32   \n"  // store 4 pixels
       "st2         {v2.16b, v3.16b}, [%1], #32   \n"  // store 4 pixels
       "b.gt        1b                            \n"
@@ -2066,14 +2596,14 @@
                         int width) {
   asm volatile(
       "ldr         q4, [%3]                      \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q2, [%0], #32             \n"  // load 8 pixels
+      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "tbl         v0.16b, {v0.16b}, v4.16b      \n"
       "tbl         v2.16b, {v2.16b}, v4.16b      \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "mov         v1.16b, v0.16b                \n"
       "mov         v3.16b, v2.16b                \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "st2         {v0.16b, v1.16b}, [%1], #32   \n"  // store 4 pixels
       "st2         {v2.16b, v3.16b}, [%1], #32   \n"  // store 4 pixels
       "b.gt        1b                            \n"
@@ -2088,7 +2618,7 @@
                         uint16_t* dst_ar64,
                         int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"  // load 8 ARGB pixels
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "zip1        v2.16b, v0.16b, v0.16b        \n"
@@ -2114,7 +2644,7 @@
                         int width) {
   asm volatile(
       "ldp         q6, q7, [%3]                  \n"  // 2 shufflers
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"  // load 8 pixels
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "tbl         v2.16b, {v0.16b}, v6.16b      \n"  // ARGB to AB64
@@ -2140,13 +2670,13 @@
                         int width) {
   asm volatile(
       "ldr         q4, [%3]                      \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"  // load 4 pixels
       "ldp         q2, q3, [%0], #32             \n"  // load 4 pixels
+      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "tbl         v0.16b, {v0.16b, v1.16b}, v4.16b \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "tbl         v2.16b, {v2.16b, v3.16b}, v4.16b \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "stp         q0, q2, [%1], #32             \n"  // store 8 pixels
       "b.gt        1b                            \n"
       : "+r"(src_ar64),           // %0
@@ -2164,13 +2694,13 @@
                         int width) {
   asm volatile(
       "ldr         q4, [%3]                      \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"  // load 4 pixels
       "ldp         q2, q3, [%0], #32             \n"  // load 4 pixels
+      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "tbl         v0.16b, {v0.16b, v1.16b}, v4.16b \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "tbl         v2.16b, {v2.16b, v3.16b}, v4.16b \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "stp         q0, q2, [%1], #32             \n"  // store 8 pixels
       "b.gt        1b                            \n"
       : "+r"(src_ab64),           // %0
@@ -2184,7 +2714,7 @@
                               uint8_t* dst_a,
                               int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16
       "prfm        pldl1keep, [%0, 448]          \n"
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
@@ -2198,17 +2728,19 @@
   );
 }
 
+// Coefficients expressed as negatives to allow 128
 struct RgbUVConstants {
-  uint8_t kRGBToU[4];
-  uint8_t kRGBToV[4];
+  int8_t kRGBToU[4];
+  int8_t kRGBToV[4];
 };
 
 // 8x1 pixels.
-void ARGBToUV444MatrixRow_NEON(const uint8_t* src_argb,
-                               uint8_t* dst_u,
-                               uint8_t* dst_v,
-                               int width,
-                               const struct RgbUVConstants* rgbuvconstants) {
+static void ARGBToUV444MatrixRow_NEON(
+    const uint8_t* src_argb,
+    uint8_t* dst_u,
+    uint8_t* dst_v,
+    int width,
+    const struct RgbUVConstants* rgbuvconstants) {
   asm volatile(
       "ldr         d0, [%4]                      \n"  // load rgbuvconstants
       "dup         v24.16b, v0.b[0]              \n"  // UB  0.875 coefficient
@@ -2216,9 +2748,10 @@
       "dup         v26.16b, v0.b[2]              \n"  // UR -0.2969 coefficient
       "dup         v27.16b, v0.b[4]              \n"  // VB -0.1406 coefficient
       "dup         v28.16b, v0.b[5]              \n"  // VG -0.7344 coefficient
-      "movi        v29.16b, #0x80                \n"  // 128.5
+      "neg         v24.16b, v24.16b              \n"
+      "movi        v29.8h, #0x80, lsl #8         \n"  // 128.0
 
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
       "umull       v4.8h, v0.8b, v24.8b          \n"  // B
@@ -2230,8 +2763,8 @@
       "umlsl       v3.8h, v1.8b, v28.8b          \n"  // G
       "umlsl       v3.8h, v0.8b, v27.8b          \n"  // B
 
-      "addhn       v0.8b, v4.8h, v29.8h          \n"  // +128 -> unsigned
-      "addhn       v1.8b, v3.8h, v29.8h          \n"  // +128 -> unsigned
+      "addhn       v0.8b, v4.8h, v29.8h          \n"  // signed -> unsigned
+      "addhn       v1.8b, v3.8h, v29.8h          \n"
 
       "st1         {v0.8b}, [%1], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%2], #8             \n"  // store 8 pixels V.
@@ -2245,51 +2778,104 @@
         "v27", "v28", "v29");
 }
 
-// RGB to bt601 coefficients
+static void ARGBToUV444MatrixRow_NEON_I8MM(
+    const uint8_t* src_argb,
+    uint8_t* dst_u,
+    uint8_t* dst_v,
+    int width,
+    const struct RgbUVConstants* rgbuvconstants) {
+  asm volatile(
+      "ld2r        {v16.4s, v17.4s}, [%[rgbuvconstants]] \n"
+      "movi        v29.8h, #0x80, lsl #8         \n"  // 128.0
+      "1:          \n"
+      "ldp         q0, q1, [%[src]], #32         \n"
+      "subs        %w[width], %w[width], #8      \n"  // 8 processed per loop.
+      "movi        v2.4s, #0                     \n"
+      "movi        v3.4s, #0                     \n"
+      "movi        v4.4s, #0                     \n"
+      "movi        v5.4s, #0                     \n"
+      "usdot       v2.4s, v0.16b, v16.16b        \n"
+      "usdot       v3.4s, v1.16b, v16.16b        \n"
+      "usdot       v4.4s, v0.16b, v17.16b        \n"
+      "usdot       v5.4s, v1.16b, v17.16b        \n"
+      "prfm        pldl1keep, [%[src], 448]      \n"
+      "uzp1        v0.8h, v2.8h, v3.8h           \n"
+      "uzp1        v1.8h, v4.8h, v5.8h           \n"
+      "subhn       v0.8b, v29.8h, v0.8h          \n"  // -signed -> unsigned
+      "subhn       v1.8b, v29.8h, v1.8h          \n"
+      "str         d0, [%[dst_u]], #8            \n"  // store 8 pixels U.
+      "str         d1, [%[dst_v]], #8            \n"  // store 8 pixels V.
+      "b.gt        1b                            \n"
+      : [src] "+r"(src_argb),                 // %[src]
+        [dst_u] "+r"(dst_u),                  // %[dst_u]
+        [dst_v] "+r"(dst_v),                  // %[dst_v]
+        [width] "+r"(width)                   // %[width]
+      : [rgbuvconstants] "r"(rgbuvconstants)  // %[rgbuvconstants]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17",
+        "v29");
+}
+
+// RGB to BT601 coefficients
 // UB   0.875 coefficient = 112
-// UG -0.5781 coefficient = 74
-// UR -0.2969 coefficient = 38
-// VB -0.1406 coefficient = 18
-// VG -0.7344 coefficient = 94
-// VR   0.875 coefficient = 112 (ignored)
+// UG -0.5781 coefficient = -74
+// UR -0.2969 coefficient = -38
+// VB -0.1406 coefficient = -18
+// VG -0.7344 coefficient = -94
+// VR   0.875 coefficient = 112
 
-static const struct RgbUVConstants kRgb24I601UVConstants = {{112, 74, 38, 0},
-                                                            {18, 94, 112, 0}};
-
-// RGB to JPeg coefficients
-// UB coeff 0.500    = 127
-// UG coeff -0.33126 = 84
-// UR coeff -0.16874 = 43
-// VB coeff -0.08131 = 20
-// VG coeff -0.41869 = 107
-// VR coeff 0.500    = 127 (ignored)
-
-static const struct RgbUVConstants kRgb24JPegUVConstants = {{127, 84, 43, 0},
-                                                            {20, 107, 127, 0}};
+static const struct RgbUVConstants kARGBI601UVConstants = {{-112, 74, 38, 0},
+                                                           {18, 94, -112, 0}};
 
 void ARGBToUV444Row_NEON(const uint8_t* src_argb,
                          uint8_t* dst_u,
                          uint8_t* dst_v,
                          int width) {
   ARGBToUV444MatrixRow_NEON(src_argb, dst_u, dst_v, width,
-                            &kRgb24I601UVConstants);
+                            &kARGBI601UVConstants);
 }
 
+void ARGBToUV444Row_NEON_I8MM(const uint8_t* src_argb,
+                              uint8_t* dst_u,
+                              uint8_t* dst_v,
+                              int width) {
+  ARGBToUV444MatrixRow_NEON_I8MM(src_argb, dst_u, dst_v, width,
+                                 &kARGBI601UVConstants);
+}
+
+// RGB to JPEG coefficients
+// UB  0.500    coefficient = 128
+// UG -0.33126  coefficient = -85
+// UR -0.16874  coefficient = -43
+// VB -0.08131  coefficient = -21
+// VG -0.41869  coefficient = -107
+// VR 0.500     coefficient = 128
+
+static const struct RgbUVConstants kARGBJPEGUVConstants = {{-128, 85, 43, 0},
+                                                           {21, 107, -128, 0}};
+
 void ARGBToUVJ444Row_NEON(const uint8_t* src_argb,
                           uint8_t* dst_u,
                           uint8_t* dst_v,
                           int width) {
   ARGBToUV444MatrixRow_NEON(src_argb, dst_u, dst_v, width,
-                            &kRgb24JPegUVConstants);
+                            &kARGBJPEGUVConstants);
+}
+
+void ARGBToUVJ444Row_NEON_I8MM(const uint8_t* src_argb,
+                               uint8_t* dst_u,
+                               uint8_t* dst_v,
+                               int width) {
+  ARGBToUV444MatrixRow_NEON_I8MM(src_argb, dst_u, dst_v, width,
+                                 &kARGBJPEGUVConstants);
 }
 
 #define RGBTOUV_SETUP_REG                                                  \
-  "movi       v20.8h, #56, lsl #0  \n" /* UB/VR coefficient (0.875) / 2 */ \
-  "movi       v21.8h, #37, lsl #0  \n" /* UG coefficient (-0.5781) / 2  */ \
-  "movi       v22.8h, #19, lsl #0  \n" /* UR coefficient (-0.2969) / 2  */ \
-  "movi       v23.8h, #9,  lsl #0  \n" /* VB coefficient (-0.1406) / 2  */ \
-  "movi       v24.8h, #47, lsl #0  \n" /* VG coefficient (-0.7344) / 2  */ \
-  "movi       v25.16b, #0x80       \n" /* 128.5 (0x8080 in 16-bit)      */
+  "movi       v20.8h, #112          \n" /* UB/VR coefficient  (0.875)   */ \
+  "movi       v21.8h, #74           \n" /* UG coefficient    (-0.5781)  */ \
+  "movi       v22.8h, #38           \n" /* UR coefficient    (-0.2969)  */ \
+  "movi       v23.8h, #18           \n" /* VB coefficient    (-0.1406)  */ \
+  "movi       v24.8h, #94           \n" /* VG coefficient    (-0.7344)  */ \
+  "movi       v25.8h, #0x80, lsl #8 \n" /* 128.0 (0x8000 in 16-bit) */
 
 // 16x2 pixels -> 8x1.  width is number of argb pixels. e.g. 16.
 // clang-format off
@@ -2315,8 +2901,9 @@
   const uint8_t* src_argb_1 = src_argb + src_stride_argb;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2328,11 +2915,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2348,7 +2934,6 @@
   );
 }
 
-// TODO(fbarchard): Subsample match Intel code.
 void ARGBToUVJRow_NEON(const uint8_t* src_argb,
                        int src_stride_argb,
                        uint8_t* dst_u,
@@ -2356,14 +2941,15 @@
                        int width) {
   const uint8_t* src_argb_1 = src_argb + src_stride_argb;
   asm volatile (
-      "movi        v20.8h, #63, lsl #0           \n"  // UB/VR coeff (0.500) / 2
-      "movi        v21.8h, #42, lsl #0           \n"  // UG coeff (-0.33126) / 2
-      "movi        v22.8h, #21, lsl #0           \n"  // UR coeff (-0.16874) / 2
-      "movi        v23.8h, #10, lsl #0           \n"  // VB coeff (-0.08131) / 2
-      "movi        v24.8h, #53, lsl #0           \n"  // VG coeff (-0.41869) / 2
-      "movi        v25.16b, #0x80                \n"  // 128.5 (0x8080 in 16-bit)
-      "1:                                        \n"
+      "movi        v20.8h, #128                  \n"  // UB/VR coeff (0.500)
+      "movi        v21.8h, #85                   \n"  // UG coeff (-0.33126)
+      "movi        v22.8h, #43                   \n"  // UR coeff (-0.16874)
+      "movi        v23.8h, #21                   \n"  // VB coeff (-0.08131)
+      "movi        v24.8h, #107                  \n"  // VG coeff (-0.41869)
+      "movi        v25.8h, #0x80, lsl #8         \n"  // 128.0 (0x8000 in 16-bit)
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2374,11 +2960,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2401,14 +2986,15 @@
                        int width) {
   const uint8_t* src_abgr_1 = src_abgr + src_stride_abgr;
   asm volatile (
-      "movi        v20.8h, #63, lsl #0           \n"  // UB/VR coeff (0.500) / 2
-      "movi        v21.8h, #42, lsl #0           \n"  // UG coeff (-0.33126) / 2
-      "movi        v22.8h, #21, lsl #0           \n"  // UR coeff (-0.16874) / 2
-      "movi        v23.8h, #10, lsl #0           \n"  // VB coeff (-0.08131) / 2
-      "movi        v24.8h, #53, lsl #0           \n"  // VG coeff (-0.41869) / 2
-      "movi        v25.16b, #0x80                \n"  // 128.5 (0x8080 in 16-bit)
-      "1:                                        \n"
+      "movi        v20.8h, #128                  \n"  // UB/VR coeff (0.500)
+      "movi        v21.8h, #85                   \n"  // UG coeff (-0.33126)
+      "movi        v22.8h, #43                   \n"  // UR coeff (-0.16874)
+      "movi        v23.8h, #21                   \n"  // VB coeff (-0.08131)
+      "movi        v24.8h, #107                  \n"  // VG coeff (-0.41869)
+      "movi        v25.8h, #0x80, lsl #8         \n"  // 128.0 (0x8000 in 16-bit)
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // R 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2419,11 +3005,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // B 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v2.8h, v1.8h, v0.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2446,14 +3031,15 @@
                         int width) {
   const uint8_t* src_rgb24_1 = src_rgb24 + src_stride_rgb24;
   asm volatile (
-      "movi        v20.8h, #63, lsl #0           \n"  // UB/VR coeff (0.500) / 2
-      "movi        v21.8h, #42, lsl #0           \n"  // UG coeff (-0.33126) / 2
-      "movi        v22.8h, #21, lsl #0           \n"  // UR coeff (-0.16874) / 2
-      "movi        v23.8h, #10, lsl #0           \n"  // VB coeff (-0.08131) / 2
-      "movi        v24.8h, #53, lsl #0           \n"  // VG coeff (-0.41869) / 2
-      "movi        v25.16b, #0x80                \n"  // 128.5 (0x8080 in 16-bit)
-      "1:                                        \n"
+      "movi        v20.8h, #128                  \n"  // UB/VR coeff (0.500)
+      "movi        v21.8h, #85                   \n"  // UG coeff (-0.33126)
+      "movi        v22.8h, #43                   \n"  // UR coeff (-0.16874)
+      "movi        v23.8h, #21                   \n"  // VB coeff (-0.08131)
+      "movi        v24.8h, #107                  \n"  // VG coeff (-0.41869)
+      "movi        v25.8h, #0x80, lsl #8         \n"  // 128.0 (0x8000 in 16-bit)
+      "1:          \n"
       "ld3         {v0.16b,v1.16b,v2.16b}, [%0], #48 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2464,11 +3050,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2491,14 +3076,15 @@
                       int width) {
   const uint8_t* src_raw_1 = src_raw + src_stride_raw;
   asm volatile (
-      "movi        v20.8h, #63, lsl #0           \n"  // UB/VR coeff (0.500) / 2
-      "movi        v21.8h, #42, lsl #0           \n"  // UG coeff (-0.33126) / 2
-      "movi        v22.8h, #21, lsl #0           \n"  // UR coeff (-0.16874) / 2
-      "movi        v23.8h, #10, lsl #0           \n"  // VB coeff (-0.08131) / 2
-      "movi        v24.8h, #53, lsl #0           \n"  // VG coeff (-0.41869) / 2
-      "movi        v25.16b, #0x80                \n"  // 128.5 (0x8080 in 16-bit)
-      "1:                                        \n"
+      "movi        v20.8h, #128                  \n"  // UB/VR coeff (0.500)
+      "movi        v21.8h, #85                   \n"  // UG coeff (-0.33126)
+      "movi        v22.8h, #43                   \n"  // UR coeff (-0.16874)
+      "movi        v23.8h, #21                   \n"  // VB coeff (-0.08131)
+      "movi        v24.8h, #107                  \n"  // VG coeff (-0.41869)
+      "movi        v25.8h, #0x80, lsl #8         \n"  // 128.0 (0x8000 in 16-bit)
+      "1:          \n"
       "ld3         {v0.16b,v1.16b,v2.16b}, [%0], #48 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2509,11 +3095,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v2.8h, v1.8h, v0.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2537,8 +3122,9 @@
   const uint8_t* src_bgra_1 = src_bgra + src_stride_bgra;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v3.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v3.8h, v2.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2549,11 +3135,10 @@
       "uadalp      v3.8h, v6.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v5.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v3.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v3.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2577,8 +3162,9 @@
   const uint8_t* src_abgr_1 = src_abgr + src_stride_abgr;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v3.8h, v2.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v2.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2589,11 +3175,10 @@
       "uadalp      v2.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v1.8h, v4.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v3.8h, #1              \n"  // 2x average
-      "urshr       v2.8h, v2.8h, #1              \n"
-      "urshr       v1.8h, v1.8h, #1              \n"
+      "urshr       v0.8h, v3.8h, #2              \n"  // average of 4
+      "urshr       v2.8h, v2.8h, #2              \n"
+      "urshr       v1.8h, v1.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v2.8h, v1.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2617,8 +3202,9 @@
   const uint8_t* src_rgba_1 = src_rgba + src_stride_rgba;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v1.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v2.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2629,11 +3215,10 @@
       "uadalp      v1.8h, v6.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v7.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2657,8 +3242,9 @@
   const uint8_t* src_rgb24_1 = src_rgb24 + src_stride_rgb24;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.16b,v1.16b,v2.16b}, [%0], #48 \n"  // load 16 pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2669,11 +3255,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v2.8h, v6.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v0.8h, v0.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v2.8h, v2.8h, #1              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2697,8 +3282,9 @@
   const uint8_t* src_raw_1 = src_raw + src_stride_raw;
   asm volatile (
     RGBTOUV_SETUP_REG
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v0.16b,v1.16b,v2.16b}, [%0], #48 \n"  // load 16 RAW pixels.
+      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
       "uaddlp      v2.8h, v2.16b                 \n"  // B 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
@@ -2709,11 +3295,10 @@
       "uadalp      v1.8h, v5.16b                 \n"  // G 16 bytes -> 8 shorts.
       "uadalp      v0.8h, v4.16b                 \n"  // R 16 bytes -> 8 shorts.
 
-      "urshr       v2.8h, v2.8h, #1              \n"  // 2x average
-      "urshr       v1.8h, v1.8h, #1              \n"
-      "urshr       v0.8h, v0.8h, #1              \n"
+      "urshr       v2.8h, v2.8h, #2              \n"  // average of 4
+      "urshr       v1.8h, v1.8h, #2              \n"
+      "urshr       v0.8h, v0.8h, #2              \n"
 
-      "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
     RGBTOUV(v2.8h, v1.8h, v0.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2738,40 +3323,26 @@
   const uint8_t* src_rgb565_1 = src_rgb565 + src_stride_rgb565;
   asm volatile(
       RGBTOUV_SETUP_REG
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 RGB565 pixels.
-      RGB565TOARGB
-      "uaddlp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "uaddlp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%0], #16           \n"  // next 8 RGB565 pixels.
-      RGB565TOARGB
-      "uaddlp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uaddlp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ld1         {v0.16b}, [%1], #16           \n"  // load 8 RGB565 pixels.
-      RGB565TOARGB
-      "uadalp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "uadalp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%1], #16           \n"  // next 8 RGB565 pixels.
-      RGB565TOARGB
-      "uadalp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uadalp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ins         v16.D[1], v26.D[0]            \n"
-      "ins         v17.D[1], v27.D[0]            \n"
-      "ins         v18.D[1], v28.D[0]            \n"
-
-      "urshr       v0.8h, v16.8h, #1             \n"  // 2x average
-      "urshr       v1.8h, v17.8h, #1             \n"
-      "urshr       v2.8h, v18.8h, #1             \n"
-
+      "1:          \n"
+      "ldp         q0, q4, [%0], #32             \n"  // load 16 RGB565 pixels.
       "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
+      RGB565TOARGB
+      "uaddlp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uaddlp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uaddlp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "ldp         q0, q4, [%1], #32             \n"  // load 16 RGB565 pixels.
+      RGB565TOARGB
+      "uadalp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "uadalp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uadalp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "urshr       v0.8h, v16.8h, #2             \n"  // average of 4
+      "urshr       v1.8h, v17.8h, #2             \n"
+      "urshr       v2.8h, v18.8h, #2             \n"
+
       RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2796,40 +3367,26 @@
   const uint8_t* src_argb1555_1 = src_argb1555 + src_stride_argb1555;
   asm volatile(
       RGBTOUV_SETUP_REG
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB1555 pixels.
-      RGB555TOARGB
-      "uaddlp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "uaddlp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%0], #16           \n"  // next 8 ARGB1555 pixels.
-      RGB555TOARGB
-      "uaddlp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uaddlp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ld1         {v0.16b}, [%1], #16           \n"  // load 8 ARGB1555 pixels.
-      RGB555TOARGB
-      "uadalp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "uadalp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%1], #16           \n"  // next 8 ARGB1555 pixels.
-      RGB555TOARGB
-      "uadalp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uadalp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ins         v16.D[1], v26.D[0]            \n"
-      "ins         v17.D[1], v27.D[0]            \n"
-      "ins         v18.D[1], v28.D[0]            \n"
-
-      "urshr       v0.8h, v16.8h, #1             \n"  // 2x average
-      "urshr       v1.8h, v17.8h, #1             \n"
-      "urshr       v2.8h, v18.8h, #1             \n"
-
+      "1:          \n"
+      "ldp         q0, q3, [%0], #32             \n"  // load 16 ARGB1555 pixels.
       "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
+      RGB555TOARGB
+      "uaddlp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uaddlp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uaddlp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "ldp         q0, q3, [%1], #32             \n"  // load 16 ARGB1555 pixels.
+      RGB555TOARGB
+      "uadalp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "uadalp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uadalp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "urshr       v0.8h, v16.8h, #2             \n"  // average of 4
+      "urshr       v1.8h, v17.8h, #2             \n"
+      "urshr       v2.8h, v18.8h, #2             \n"
+
       RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2842,7 +3399,7 @@
       :
       : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v16", "v17",
         "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
-        "v28");
+        "v28", "v29");
 }
 
 // 16x2 pixels -> 8x1.  width is number of argb pixels. e.g. 16.
@@ -2854,40 +3411,26 @@
   const uint8_t* src_argb4444_1 = src_argb4444 + src_stride_argb4444;
   asm volatile(
       RGBTOUV_SETUP_REG  // sets v20-v25
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB4444 pixels.
-      ARGB4444TOARGB
-      "uaddlp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "uaddlp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%0], #16           \n"  // next 8 ARGB4444 pixels.
-      ARGB4444TOARGB
-      "uaddlp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uaddlp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uaddlp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ld1         {v0.16b}, [%1], #16           \n"  // load 8 ARGB4444 pixels.
-      ARGB4444TOARGB
-      "uadalp      v16.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "uadalp      v17.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v18.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-      "ld1         {v0.16b}, [%1], #16           \n"  // next 8 ARGB4444 pixels.
-      ARGB4444TOARGB
-      "uadalp      v26.4h, v0.8b                 \n"  // B 8 bytes -> 4 shorts.
-      "uadalp      v27.4h, v1.8b                 \n"  // G 8 bytes -> 4 shorts.
-      "uadalp      v28.4h, v2.8b                 \n"  // R 8 bytes -> 4 shorts.
-
-      "ins         v16.D[1], v26.D[0]            \n"
-      "ins         v17.D[1], v27.D[0]            \n"
-      "ins         v18.D[1], v28.D[0]            \n"
-
-      "urshr       v0.8h, v16.8h, #1             \n"  // 2x average
-      "urshr       v1.8h, v17.8h, #1             \n"
-      "urshr       v2.8h, v18.8h, #1             \n"
-
+      "1:          \n"
+      "ldp         q0, q3, [%0], #32             \n"  // load 16 ARGB4444 pixels.
       "subs        %w4, %w4, #16                 \n"  // 16 processed per loop.
+      ARGB4444TORGB
+      "uaddlp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uaddlp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uaddlp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "ldp         q0, q3, [%1], #32             \n"  // load 16 ARGB4444 pixels.
+      ARGB4444TORGB
+      "uadalp      v16.8h, v0.16b                \n"  // B 16 bytes -> 8 shorts.
+      "prfm        pldl1keep, [%1, 448]          \n"
+      "uadalp      v17.8h, v1.16b                \n"  // G 16 bytes -> 8 shorts.
+      "uadalp      v18.8h, v2.16b                \n"  // R 16 bytes -> 8 shorts.
+
+      "urshr       v0.8h, v16.8h, #2             \n"  // average of 4
+      "urshr       v1.8h, v17.8h, #2             \n"
+      "urshr       v2.8h, v18.8h, #2             \n"
+
       RGBTOUV(v0.8h, v1.8h, v2.8h)
       "st1         {v0.8b}, [%2], #8             \n"  // store 8 pixels U.
       "st1         {v1.8b}, [%3], #8             \n"  // store 8 pixels V.
@@ -2907,21 +3450,26 @@
 
 void RGB565ToYRow_NEON(const uint8_t* src_rgb565, uint8_t* dst_y, int width) {
   asm volatile(
-      "movi        v24.8b, #25                   \n"  // B * 0.1016 coefficient
-      "movi        v25.8b, #129                  \n"  // G * 0.5078 coefficient
-      "movi        v26.8b, #66                   \n"  // R * 0.2578 coefficient
-      "movi        v27.8b, #16                   \n"  // Add 16 constant
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 RGB565 pixels.
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
+      "movi        v24.16b, #25                  \n"  // B * 0.1016 coefficient
+      "movi        v25.16b, #129                 \n"  // G * 0.5078 coefficient
+      "movi        v26.16b, #66                  \n"  // R * 0.2578 coefficient
+      "movi        v27.16b, #16                  \n"  // Add 16 constant
+      "1:          \n"
+      "ldp         q0, q4, [%0], #32             \n"  // load 16 RGB565 pixels.
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
       RGB565TOARGB
       "umull       v3.8h, v0.8b, v24.8b          \n"  // B
+      "umull2      v4.8h, v0.16b, v24.16b        \n"  // B
       "prfm        pldl1keep, [%0, 448]          \n"
       "umlal       v3.8h, v1.8b, v25.8b          \n"  // G
+      "umlal2      v4.8h, v1.16b, v25.16b        \n"  // G
       "umlal       v3.8h, v2.8b, v26.8b          \n"  // R
+      "umlal2      v4.8h, v2.16b, v26.16b        \n"  // R
       "uqrshrn     v0.8b, v3.8h, #8              \n"  // 16 bit to 8 bit Y
+      "uqrshrn     v1.8b, v4.8h, #8              \n"  // 16 bit to 8 bit Y
       "uqadd       v0.8b, v0.8b, v27.8b          \n"
-      "st1         {v0.8b}, [%1], #8             \n"  // store 8 pixels Y.
+      "uqadd       v1.8b, v1.8b, v27.8b          \n"
+      "stp         d0, d1, [%1], #16             \n"  // store 8 pixels Y.
       "b.gt        1b                            \n"
       : "+r"(src_rgb565),  // %0
         "+r"(dst_y),       // %1
@@ -2935,48 +3483,59 @@
                          uint8_t* dst_y,
                          int width) {
   asm volatile(
-      "movi        v4.8b, #25                    \n"  // B * 0.1016 coefficient
-      "movi        v5.8b, #129                   \n"  // G * 0.5078 coefficient
-      "movi        v6.8b, #66                    \n"  // R * 0.2578 coefficient
-      "movi        v7.8b, #16                    \n"  // Add 16 constant
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB1555 pixels.
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
-      ARGB1555TOARGB
-      "umull       v3.8h, v0.8b, v4.8b           \n"  // B
+      "movi        v4.16b, #25                   \n"  // B * 0.1016 coefficient
+      "movi        v5.16b, #129                  \n"  // G * 0.5078 coefficient
+      "movi        v6.16b, #66                   \n"  // R * 0.2578 coefficient
+      "movi        v7.16b, #16                   \n"  // Add 16 constant
+      "1:          \n"
+      "ldp         q0, q3, [%0], #32             \n"  // load 16 ARGB1555
+                                                      // pixels.
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
+      RGB555TOARGB
+      "umull       v16.8h, v0.8b, v4.8b          \n"  // B
+      "umull2      v17.8h, v0.16b, v4.16b        \n"  // B
       "prfm        pldl1keep, [%0, 448]          \n"
-      "umlal       v3.8h, v1.8b, v5.8b           \n"  // G
-      "umlal       v3.8h, v2.8b, v6.8b           \n"  // R
-      "uqrshrn     v0.8b, v3.8h, #8              \n"  // 16 bit to 8 bit Y
-      "uqadd       v0.8b, v0.8b, v7.8b           \n"
-      "st1         {v0.8b}, [%1], #8             \n"  // store 8 pixels Y.
+      "umlal       v16.8h, v1.8b, v5.8b          \n"  // G
+      "umlal2      v17.8h, v1.16b, v5.16b        \n"  // G
+      "umlal       v16.8h, v2.8b, v6.8b          \n"  // R
+      "umlal2      v17.8h, v2.16b, v6.16b        \n"  // R
+      "uqrshrn     v0.8b, v16.8h, #8             \n"  // 16 bit to 8 bit Y
+      "uqrshrn2    v0.16b, v17.8h, #8            \n"  // 16 bit to 8 bit Y
+      "uqadd       v0.16b, v0.16b, v7.16b        \n"
+      "str         q0, [%1], #16                 \n"  // store  pixels Y.
       "b.gt        1b                            \n"
       : "+r"(src_argb1555),  // %0
         "+r"(dst_y),         // %1
         "+r"(width)          // %2
       :
-      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
+        "v17", "v29");
 }
 
 void ARGB4444ToYRow_NEON(const uint8_t* src_argb4444,
                          uint8_t* dst_y,
                          int width) {
   asm volatile(
-      "movi        v24.8b, #25                   \n"  // B * 0.1016 coefficient
-      "movi        v25.8b, #129                  \n"  // G * 0.5078 coefficient
-      "movi        v26.8b, #66                   \n"  // R * 0.2578 coefficient
-      "movi        v27.8b, #16                   \n"  // Add 16 constant
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load 8 ARGB4444 pixels.
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
-      ARGB4444TOARGB
-      "umull       v3.8h, v0.8b, v24.8b          \n"  // B
+      "movi        v24.16b, #25                  \n"  // B * 0.1016 coefficient
+      "movi        v25.16b, #129                 \n"  // G * 0.5078 coefficient
+      "movi        v26.16b, #66                  \n"  // R * 0.2578 coefficient
+      "movi        v27.16b, #16                  \n"  // Add 16 constant
+      "1:          \n"
+      "ldp         q0, q3, [%0], #32             \n"  // load 16 ARGB4444
+                                                      // pixels.
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
+      ARGB4444TORGB
+      "umull       v16.8h, v0.8b, v24.8b         \n"  // B
+      "umull2      v17.8h, v0.16b, v24.16b       \n"  // B
       "prfm        pldl1keep, [%0, 448]          \n"
-      "umlal       v3.8h, v1.8b, v25.8b          \n"  // G
-      "umlal       v3.8h, v2.8b, v26.8b          \n"  // R
-      "uqrshrn     v0.8b, v3.8h, #8              \n"  // 16 bit to 8 bit Y
-      "uqadd       v0.8b, v0.8b, v27.8b          \n"
-      "st1         {v0.8b}, [%1], #8             \n"  // store 8 pixels Y.
+      "umlal       v16.8h, v1.8b, v25.8b         \n"  // G
+      "umlal2      v17.8h, v1.16b, v25.16b       \n"  // G
+      "umlal       v16.8h, v2.8b, v26.8b         \n"  // R
+      "umlal2      v17.8h, v2.16b, v26.16b       \n"  // R
+      "uqrshrn     v0.8b, v16.8h, #8             \n"  // 16 bit to 8 bit Y
+      "uqrshrn2    v0.16b, v17.8h, #8            \n"  // 16 bit to 8 bit Y
+      "uqadd       v0.16b, v0.16b, v27.16b       \n"
+      "str         q0, [%1], #16                 \n"  // store 8 pixels Y.
       "b.gt        1b                            \n"
       : "+r"(src_argb4444),  // %0
         "+r"(dst_y),         // %1
@@ -2991,17 +3550,17 @@
 };
 
 // ARGB expects first 3 values to contain RGB and 4th value is ignored.
-void ARGBToYMatrixRow_NEON(const uint8_t* src_argb,
-                           uint8_t* dst_y,
-                           int width,
-                           const struct RgbConstants* rgbconstants) {
+static void ARGBToYMatrixRow_NEON(const uint8_t* src_argb,
+                                  uint8_t* dst_y,
+                                  int width,
+                                  const struct RgbConstants* rgbconstants) {
   asm volatile(
       "ldr         d0, [%3]                      \n"  // load rgbconstants
       "dup         v6.16b, v0.b[0]               \n"
       "dup         v7.16b, v0.b[1]               \n"
       "dup         v16.16b, v0.b[2]              \n"
       "dup         v17.8h,  v0.h[2]              \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v2.16b,v3.16b,v4.16b,v5.16b}, [%0], #64 \n"  // load 16
                                                                  // pixels.
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
@@ -3024,14 +3583,52 @@
         "v17");
 }
 
+static void ARGBToYMatrixRow_NEON_DotProd(
+    const uint8_t* src_argb,
+    uint8_t* dst_y,
+    int width,
+    const struct RgbConstants* rgbconstants) {
+  asm volatile(
+      "ldr         d0, [%3]                      \n"  // load rgbconstants
+      "dup         v16.4s, v0.s[0]               \n"
+      "dup         v17.8h,  v0.h[2]              \n"
+      "1:          \n"
+      "ld1         {v4.16b, v5.16b, v6.16b, v7.16b}, [%0], #64 \n"  // load 16
+                                                                    // pixels.
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
+      "movi        v0.16b, #0                    \n"
+      "movi        v1.16b, #0                    \n"
+      "movi        v2.16b, #0                    \n"
+      "movi        v3.16b, #0                    \n"
+      "udot        v0.4s, v4.16b, v16.16b        \n"
+      "udot        v1.4s, v5.16b, v16.16b        \n"
+      "udot        v2.4s, v6.16b, v16.16b        \n"
+      "udot        v3.4s, v7.16b, v16.16b        \n"
+      "uzp1        v0.8h, v0.8h, v1.8h           \n"
+      "uzp1        v1.8h, v2.8h, v3.8h           \n"
+      "addhn       v0.8b, v0.8h, v17.8h          \n"
+      "addhn       v1.8b, v1.8h, v17.8h          \n"
+      "st1         {v0.8b, v1.8b}, [%1], #16     \n"  // store 16 pixels Y.
+      "b.gt        1b                            \n"
+      : "+r"(src_argb),    // %0
+        "+r"(dst_y),       // %1
+        "+r"(width)        // %2
+      : "r"(rgbconstants)  // %3
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
+        "v17");
+}
+
 // RGB to JPeg coefficients
 // B * 0.1140 coefficient = 29
 // G * 0.5870 coefficient = 150
 // R * 0.2990 coefficient = 77
-// Add 0.5 = 0x80
-static const struct RgbConstants kRgb24JPEGConstants = {{29, 150, 77, 0}, 128};
+// Add 0.5
+static const struct RgbConstants kRgb24JPEGConstants = {{29, 150, 77, 0},
+                                                        0x0080};
+static const struct RgbConstants kRgb24JPEGDotProdConstants = {{0, 29, 150, 77},
+                                                               0x0080};
 
-static const struct RgbConstants kRawJPEGConstants = {{77, 150, 29, 0}, 128};
+static const struct RgbConstants kRawJPEGConstants = {{77, 150, 29, 0}, 0x0080};
 
 // RGB to BT.601 coefficients
 // B * 0.1016 coefficient = 25
@@ -3041,8 +3638,12 @@
 
 static const struct RgbConstants kRgb24I601Constants = {{25, 129, 66, 0},
                                                         0x1080};
+static const struct RgbConstants kRgb24I601DotProdConstants = {{0, 25, 129, 66},
+                                                               0x1080};
 
 static const struct RgbConstants kRawI601Constants = {{66, 129, 25, 0}, 0x1080};
+static const struct RgbConstants kRawI601DotProdConstants = {{0, 66, 129, 25},
+                                                             0x1080};
 
 void ARGBToYRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width) {
   ARGBToYMatrixRow_NEON(src_argb, dst_y, width, &kRgb24I601Constants);
@@ -3060,19 +3661,43 @@
   ARGBToYMatrixRow_NEON(src_abgr, dst_yj, width, &kRawJPEGConstants);
 }
 
+void ARGBToYRow_NEON_DotProd(const uint8_t* src_argb,
+                             uint8_t* dst_y,
+                             int width) {
+  ARGBToYMatrixRow_NEON_DotProd(src_argb, dst_y, width, &kRgb24I601Constants);
+}
+
+void ARGBToYJRow_NEON_DotProd(const uint8_t* src_argb,
+                              uint8_t* dst_yj,
+                              int width) {
+  ARGBToYMatrixRow_NEON_DotProd(src_argb, dst_yj, width, &kRgb24JPEGConstants);
+}
+
+void ABGRToYRow_NEON_DotProd(const uint8_t* src_abgr,
+                             uint8_t* dst_y,
+                             int width) {
+  ARGBToYMatrixRow_NEON_DotProd(src_abgr, dst_y, width, &kRawI601Constants);
+}
+
+void ABGRToYJRow_NEON_DotProd(const uint8_t* src_abgr,
+                              uint8_t* dst_yj,
+                              int width) {
+  ARGBToYMatrixRow_NEON_DotProd(src_abgr, dst_yj, width, &kRawJPEGConstants);
+}
+
 // RGBA expects first value to be A and ignored, then 3 values to contain RGB.
 // Same code as ARGB, except the LD4
-void RGBAToYMatrixRow_NEON(const uint8_t* src_rgba,
-                           uint8_t* dst_y,
-                           int width,
-                           const struct RgbConstants* rgbconstants) {
+static void RGBAToYMatrixRow_NEON(const uint8_t* src_rgba,
+                                  uint8_t* dst_y,
+                                  int width,
+                                  const struct RgbConstants* rgbconstants) {
   asm volatile(
       "ldr         d0, [%3]                      \n"  // load rgbconstants
       "dup         v6.16b, v0.b[0]               \n"
       "dup         v7.16b, v0.b[1]               \n"
       "dup         v16.16b, v0.b[2]              \n"
       "dup         v17.8h,  v0.h[2]              \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v1.16b,v2.16b,v3.16b,v4.16b}, [%0], #64 \n"  // load 16
                                                                  // pixels.
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
@@ -3107,17 +3732,44 @@
   RGBAToYMatrixRow_NEON(src_bgra, dst_y, width, &kRawI601Constants);
 }
 
-void RGBToYMatrixRow_NEON(const uint8_t* src_rgb,
-                          uint8_t* dst_y,
-                          int width,
-                          const struct RgbConstants* rgbconstants) {
+void RGBAToYRow_NEON_DotProd(const uint8_t* src_rgba,
+                             uint8_t* dst_y,
+                             int width) {
+  // No need for a separate implementation for RGBA inputs, just permute the
+  // RGB constants.
+  ARGBToYMatrixRow_NEON_DotProd(src_rgba, dst_y, width,
+                                &kRgb24I601DotProdConstants);
+}
+
+void RGBAToYJRow_NEON_DotProd(const uint8_t* src_rgba,
+                              uint8_t* dst_yj,
+                              int width) {
+  // No need for a separate implementation for RGBA inputs, just permute the
+  // RGB constants.
+  ARGBToYMatrixRow_NEON_DotProd(src_rgba, dst_yj, width,
+                                &kRgb24JPEGDotProdConstants);
+}
+
+void BGRAToYRow_NEON_DotProd(const uint8_t* src_bgra,
+                             uint8_t* dst_y,
+                             int width) {
+  // No need for a separate implementation for RGBA inputs, just permute the
+  // RGB constants.
+  ARGBToYMatrixRow_NEON_DotProd(src_bgra, dst_y, width,
+                                &kRawI601DotProdConstants);
+}
+
+static void RGBToYMatrixRow_NEON(const uint8_t* src_rgb,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
   asm volatile(
       "ldr         d0, [%3]                      \n"  // load rgbconstants
       "dup         v5.16b, v0.b[0]               \n"
       "dup         v6.16b, v0.b[1]               \n"
       "dup         v7.16b, v0.b[2]               \n"
       "dup         v16.8h,  v0.h[2]              \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld3         {v2.16b,v3.16b,v4.16b}, [%0], #48 \n"  // load 16 pixels.
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop.
       "umull       v0.8h, v2.8b, v5.8b           \n"  // B
@@ -3172,7 +3824,7 @@
       "dup         v5.16b, %w4                   \n"
       "dup         v4.16b, %w5                   \n"
       // General purpose row blend.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%1], #16           \n"
       "ld1         {v1.16b}, [%2], #16           \n"
       "subs        %w3, %w3, #16                 \n"
@@ -3189,7 +3841,7 @@
       "b           99f                           \n"
 
       // Blend 50 / 50.
-      "50:                                       \n"
+      "50:         \n"
       "ld1         {v0.16b}, [%1], #16           \n"
       "ld1         {v1.16b}, [%2], #16           \n"
       "subs        %w3, %w3, #16                 \n"
@@ -3201,14 +3853,14 @@
       "b           99f                           \n"
 
       // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
+      "100:        \n"
       "ld1         {v0.16b}, [%1], #16           \n"
       "subs        %w3, %w3, #16                 \n"
       "prfm        pldl1keep, [%1, 448]          \n"
       "st1         {v0.16b}, [%0], #16           \n"
       "b.gt        100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),      // %0
         "+r"(src_ptr),      // %1
         "+r"(src_ptr1),     // %2
@@ -3238,7 +3890,7 @@
       "dup         v5.8h, %w4                    \n"
       "dup         v4.8h, %w5                    \n"
       // General purpose row blend.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%1], #16            \n"
       "ld1         {v1.8h}, [%2], #16            \n"
       "subs        %w3, %w3, #8                  \n"
@@ -3255,7 +3907,7 @@
       "b           99f                           \n"
 
       // Blend 50 / 50.
-      "50:                                       \n"
+      "50:         \n"
       "ld1         {v0.8h}, [%1], #16            \n"
       "ld1         {v1.8h}, [%2], #16            \n"
       "subs        %w3, %w3, #8                  \n"
@@ -3267,14 +3919,14 @@
       "b           99f                           \n"
 
       // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
+      "100:        \n"
       "ld1         {v0.8h}, [%1], #16            \n"
       "subs        %w3, %w3, #8                  \n"
       "prfm        pldl1keep, [%1, 448]          \n"
       "st1         {v0.8h}, [%0], #16            \n"
       "b.gt        100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),     // %0
         "+r"(src_ptr),     // %1
         "+r"(src_ptr1),    // %2
@@ -3311,7 +3963,7 @@
       "dup         v5.8h, %w4                    \n"
       "dup         v4.8h, %w5                    \n"
       // General purpose row blend.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%1], #16            \n"
       "ld1         {v1.8h}, [%2], #16            \n"
       "subs        %w3, %w3, #8                  \n"
@@ -3330,7 +3982,7 @@
       "b           99f                           \n"
 
       // Blend 50 / 50.
-      "50:                                       \n"
+      "50:         \n"
       "ld1         {v0.8h}, [%1], #16            \n"
       "ld1         {v1.8h}, [%2], #16            \n"
       "subs        %w3, %w3, #8                  \n"
@@ -3344,7 +3996,7 @@
       "b           99f                           \n"
 
       // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
+      "100:        \n"
       "ldr         q0, [%1], #16                 \n"
       "ushl        v0.8h, v0.8h, v2.8h           \n"  // shr = v2 is negative
       "prfm        pldl1keep, [%1, 448]          \n"
@@ -3353,7 +4005,7 @@
       "str         d0, [%0], #8                  \n"  // store 8 pixels
       "b.gt        100b                          \n"
 
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),     // %0
         "+r"(src_ptr),     // %1
         "+r"(src_ptr1),    // %2
@@ -3373,7 +4025,7 @@
       "subs        %w3, %w3, #8                  \n"
       "b.lt        89f                           \n"
       // Blend 8 pixels.
-      "8:                                        \n"
+      "8:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB0
       "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load 8 ARGB1
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
@@ -3396,12 +4048,12 @@
                                                              // pixels
       "b.ge        8b                            \n"
 
-      "89:                                       \n"
+      "89:         \n"
       "adds        %w3, %w3, #8-1                \n"
       "b.lt        99f                           \n"
 
       // Blend 1 pixels.
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.b,v1.b,v2.b,v3.b}[0], [%0], #4 \n"  // load 1 pixel
                                                            // ARGB0.
       "ld4         {v4.b,v5.b,v6.b,v7.b}[0], [%1], #4 \n"  // load 1 pixel
@@ -3425,7 +4077,7 @@
       "st4         {v0.b,v1.b,v2.b,v3.b}[0], [%2], #4 \n"  // store 1 pixel.
       "b.ge        1b                            \n"
 
-      "99:                                       \n"
+      "99:         \n"
 
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
@@ -3444,7 +4096,7 @@
       "movi        v7.8h, #0x00ff                \n"  // 255 for rounding up
 
       // Attenuate 8 pixels.
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "umull       v4.8h, v0.8b, v3.8b           \n"  // b * a
@@ -3477,7 +4129,7 @@
       "dup         v6.8h, %w4                    \n"  // interval add
 
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0] \n"  // load 8  ARGB.
       "subs        %w1, %w1, #8                  \n"    // 8 processed per loop.
       "uxtl        v0.8h, v0.8b                  \n"    // b (0 .. 255)
@@ -3507,35 +4159,36 @@
 }
 
 // Shade 8 pixels at a time by specified value.
-// NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8.
-// Rounding in vqrdmulh does +1 to high if high bit of low s16 is set.
+// sqrdmulh is a rounding instruction, so +1 if high bit of low half of
+// multiply result is set.
 void ARGBShadeRow_NEON(const uint8_t* src_argb,
                        uint8_t* dst_argb,
                        int width,
                        uint32_t value) {
   asm volatile(
       "dup         v0.4s, %w3                    \n"  // duplicate scale value.
-      "zip1        v0.8b, v0.8b, v0.8b           \n"  // v0.8b aarrggbb.
+      "zip1        v0.16b, v0.16b, v0.16b        \n"  // v0.16b
+                                                      // aarrggbbaarrggbb.
       "ushr        v0.8h, v0.8h, #1              \n"  // scale / 2.
 
       // 8 pixel loop.
-      "1:                                        \n"
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%0], #32 \n"  // load 8 ARGB
+      "1:          \n"
+      "ld1         {v4.8b,v5.8b,v6.8b,v7.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
-      "uxtl        v4.8h, v4.8b                  \n"  // b (0 .. 255)
+      "uxtl        v4.8h, v4.8b                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "uxtl        v5.8h, v5.8b                  \n"
       "uxtl        v6.8h, v6.8b                  \n"
       "uxtl        v7.8h, v7.8b                  \n"
-      "sqrdmulh    v4.8h, v4.8h, v0.h[0]         \n"  // b * scale * 2
-      "sqrdmulh    v5.8h, v5.8h, v0.h[1]         \n"  // g
-      "sqrdmulh    v6.8h, v6.8h, v0.h[2]         \n"  // r
-      "sqrdmulh    v7.8h, v7.8h, v0.h[3]         \n"  // a
+      "sqrdmulh    v4.8h, v4.8h, v0.8h           \n"  // argb * scale * 2
+      "sqrdmulh    v5.8h, v5.8h, v0.8h           \n"
+      "sqrdmulh    v6.8h, v6.8h, v0.8h           \n"
+      "sqrdmulh    v7.8h, v7.8h, v0.8h           \n"
       "uqxtn       v4.8b, v4.8h                  \n"
       "uqxtn       v5.8b, v5.8h                  \n"
       "uqxtn       v6.8b, v6.8h                  \n"
       "uqxtn       v7.8b, v7.8h                  \n"
-      "st4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // store 8 ARGB
+      "st1         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_argb),  // %0
         "+r"(dst_argb),  // %1
@@ -3552,7 +4205,7 @@
       "movi        v24.8b, #29                   \n"  // B * 0.1140 coefficient
       "movi        v25.8b, #150                  \n"  // G * 0.5870 coefficient
       "movi        v26.8b, #77                   \n"  // R * 0.2990 coefficient
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "umull       v4.8h, v0.8b, v24.8b          \n"  // B
@@ -3560,8 +4213,8 @@
       "umlal       v4.8h, v1.8b, v25.8b          \n"  // G
       "umlal       v4.8h, v2.8b, v26.8b          \n"  // R
       "uqrshrn     v0.8b, v4.8h, #8              \n"  // 16 bit to 8 bit B
-      "orr         v1.8b, v0.8b, v0.8b           \n"  // G
-      "orr         v2.8b, v0.8b, v0.8b           \n"  // R
+      "mov         v1.8b, v0.8b                  \n"  // G
+      "mov         v2.8b, v0.8b                  \n"  // R
       "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%1], #32 \n"  // store 8 pixels.
       "b.gt        1b                            \n"
       : "+r"(src_argb),  // %0
@@ -3571,6 +4224,38 @@
       : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v24", "v25", "v26");
 }
 
+static const uvec8 kARGBGrayRowCoeffs = {29, 150, 77, 0};
+static const uvec8 kARGBGrayRowIndices = {0, 0, 0, 19, 2, 2, 2, 23,
+                                          4, 4, 4, 27, 6, 6, 6, 31};
+
+void ARGBGrayRow_NEON_DotProd(const uint8_t* src_argb,
+                              uint8_t* dst_argb,
+                              int width) {
+  asm volatile(
+      "ld1r        {v24.4s}, [%[coeffs]]         \n"
+      "ldr         q25, [%[indices]]             \n"
+      "1:          \n"
+      "ldp         q1, q3, [%[src]], #32         \n"  // load 8 ARGB
+      "subs        %w[width], %w[width], #8      \n"  // 8 processed per loop
+      "movi        v0.4s, #0                     \n"
+      "movi        v2.4s, #0                     \n"
+      "udot        v0.4s, v1.16b, v24.16b        \n"
+      "udot        v2.4s, v3.16b, v24.16b        \n"
+      "prfm        pldl1keep, [%[src], 448]      \n"
+      "uqrshrn     v0.8b, v0.8h, #8              \n"
+      "uqrshrn     v2.8b, v2.8h, #8              \n"
+      "tbl         v0.16b, {v0.16b, v1.16b}, v25.16b \n"  // merge in alpha
+      "tbl         v1.16b, {v2.16b, v3.16b}, v25.16b \n"
+      "stp         q0, q1, [%[dst]], #32         \n"  // store 8 pixels
+      "b.gt        1b                            \n"
+      : [src] "+r"(src_argb),                // %[src]
+        [dst] "+r"(dst_argb),                // %[dst]
+        [width] "+r"(width)                  // %[width]
+      : [coeffs] "r"(&kARGBGrayRowCoeffs),   // %[coeffs]
+        [indices] "r"(&kARGBGrayRowIndices)  // %[indices]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v24", "v25");
+}
+
 // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
 //    b = (r * 35 + g * 68 + b * 17) >> 7
 //    g = (r * 45 + g * 88 + b * 22) >> 7
@@ -3587,7 +4272,7 @@
       "movi        v28.8b, #24                   \n"  // BB coefficient
       "movi        v29.8b, #98                   \n"  // BG coefficient
       "movi        v30.8b, #50                   \n"  // BR coefficient
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0] \n"  // load 8 ARGB pixels.
       "subs        %w1, %w1, #8                  \n"    // 8 processed per loop.
       "umull       v4.8h, v0.8b, v20.8b          \n"    // B to Sepia B
@@ -3612,6 +4297,47 @@
         "v21", "v22", "v24", "v25", "v26", "v28", "v29", "v30");
 }
 
+static const uvec8 kARGBSepiaRowCoeffs = {17, 68, 35, 0,  22, 88,
+                                          45, 0,  24, 98, 50, 0};
+static const uvec8 kARGBSepiaRowAlphaIndices = {3, 7, 11, 15, 19, 23, 27, 31};
+
+void ARGBSepiaRow_NEON_DotProd(uint8_t* dst_argb, int width) {
+  asm volatile(
+      "ld3r        {v20.4s, v21.4s, v22.4s}, [%[coeffs]] \n"
+      "ldr         d23, [%[indices]]             \n"
+      "1:          \n"
+      "ldp         q0, q1, [%[dst]]              \n"
+      "subs        %w1, %w1, #8                  \n"
+      "movi        v2.4s, #0                     \n"
+      "movi        v3.4s, #0                     \n"
+      "movi        v4.4s, #0                     \n"
+      "movi        v5.4s, #0                     \n"
+      "movi        v6.4s, #0                     \n"
+      "movi        v7.4s, #0                     \n"
+      "udot        v2.4s, v0.16b, v20.16b        \n"
+      "udot        v3.4s, v1.16b, v20.16b        \n"
+      "udot        v4.4s, v0.16b, v21.16b        \n"
+      "udot        v5.4s, v1.16b, v21.16b        \n"
+      "udot        v6.4s, v0.16b, v22.16b        \n"
+      "udot        v7.4s, v1.16b, v22.16b        \n"
+      "prfm        pldl1keep, [%[dst], 448]      \n"
+      "uzp1        v6.8h, v6.8h, v7.8h           \n"
+      "uzp1        v5.8h, v4.8h, v5.8h           \n"
+      "uzp1        v4.8h, v2.8h, v3.8h           \n"
+      "tbl         v3.16b, {v0.16b, v1.16b}, v23.16b \n"
+      "uqshrn      v0.8b, v4.8h, #7              \n"
+      "uqshrn      v1.8b, v5.8h, #7              \n"
+      "uqshrn      v2.8b, v6.8h, #7              \n"
+      "st4         {v0.8b, v1.8b, v2.8b, v3.8b}, [%[dst]], #32 \n"
+      "b.gt        1b                            \n"
+      : [dst] "+r"(dst_argb),                      // %[dst]
+        [width] "+r"(width)                        // %[width]
+      : [coeffs] "r"(&kARGBSepiaRowCoeffs),        // %[coeffs]
+        [indices] "r"(&kARGBSepiaRowAlphaIndices)  // %[indices]
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20",
+        "v21", "v22", "v24", "v25", "v26", "v28", "v29", "v30");
+}
+
 // Tranform 8 ARGB pixels (32 bytes) with color matrix.
 // TODO(fbarchard): Was same as Sepia except matrix is provided.  This function
 // needs to saturate.  Consider doing a non-saturating version.
@@ -3624,7 +4350,7 @@
       "sxtl        v0.8h, v2.8b                  \n"  // B,G coefficients s16.
       "sxtl2       v1.8h, v2.16b                 \n"  // R,A coefficients s16.
 
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%0], #32 \n"  // load 8 ARGB
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "uxtl        v16.8h, v16.8b                \n"  // b (0 .. 255) 16 bit
@@ -3674,7 +4400,62 @@
         "v17", "v18", "v19", "v22", "v23", "v24", "v25");
 }
 
-// TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable.
+void ARGBColorMatrixRow_NEON_I8MM(const uint8_t* src_argb,
+                                  uint8_t* dst_argb,
+                                  const int8_t* matrix_argb,
+                                  int width) {
+  asm volatile(
+      "ld1         {v31.16b}, [%[matrix_argb]]   \n"
+
+      "1:          \n"
+      "ld1         {v0.16b, v1.16b}, [%[src_argb]], #32 \n"
+      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
+
+      "movi        v16.4s, #0                    \n"
+      "movi        v17.4s, #0                    \n"
+      "movi        v18.4s, #0                    \n"
+      "movi        v19.4s, #0                    \n"
+      "movi        v20.4s, #0                    \n"
+      "movi        v21.4s, #0                    \n"
+      "movi        v22.4s, #0                    \n"
+      "movi        v23.4s, #0                    \n"
+
+      "prfm        pldl1keep, [%[src_argb], 448] \n"
+
+      "sudot       v16.4s, v31.16b, v0.4b[0]     \n"
+      "sudot       v17.4s, v31.16b, v0.4b[1]     \n"
+      "sudot       v18.4s, v31.16b, v0.4b[2]     \n"
+      "sudot       v19.4s, v31.16b, v0.4b[3]     \n"
+      "sudot       v20.4s, v31.16b, v1.4b[0]     \n"
+      "sudot       v21.4s, v31.16b, v1.4b[1]     \n"
+      "sudot       v22.4s, v31.16b, v1.4b[2]     \n"
+      "sudot       v23.4s, v31.16b, v1.4b[3]     \n"
+
+      "shrn        v16.4h, v16.4s, #6            \n"
+      "shrn        v18.4h, v18.4s, #6            \n"
+      "shrn        v20.4h, v20.4s, #6            \n"
+      "shrn        v22.4h, v22.4s, #6            \n"
+      "shrn2       v16.8h, v17.4s, #6            \n"
+      "shrn2       v18.8h, v19.4s, #6            \n"
+      "shrn2       v20.8h, v21.4s, #6            \n"
+      "shrn2       v22.8h, v23.4s, #6            \n"
+
+      "uqxtn       v16.8b, v16.8h                \n"
+      "uqxtn       v18.8b, v18.8h                \n"
+      "uqxtn       v20.8b, v20.8h                \n"
+      "uqxtn       v22.8b, v22.8h                \n"
+
+      "stp         d16, d18, [%[dst_argb]], #16  \n"
+      "stp         d20, d22, [%[dst_argb]], #16  \n"
+      "b.gt        1b                            \n"
+      : [src_argb] "+r"(src_argb),      // %[src_argb]
+        [dst_argb] "+r"(dst_argb),      // %[dst_argb]
+        [width] "+r"(width)             // %[width]
+      : [matrix_argb] "r"(matrix_argb)  // %[matrix_argb]
+      : "cc", "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v20", "v21",
+        "v22", "v23", "v31");
+}
+
 // Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
 void ARGBMultiplyRow_NEON(const uint8_t* src_argb,
                           const uint8_t* src_argb1,
@@ -3682,9 +4463,9 @@
                           int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load 8 more
+      "1:          \n"
+      "ld1         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
+      "ld1         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load 8 more
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
       "umull       v0.8h, v0.8b, v4.8b           \n"  // multiply B
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -3696,7 +4477,7 @@
       "rshrn       v1.8b, v1.8h, #8              \n"  // 16 bit to 8 bit G
       "rshrn       v2.8b, v2.8h, #8              \n"  // 16 bit to 8 bit R
       "rshrn       v3.8b, v3.8h, #8              \n"  // 16 bit to 8 bit A
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"  // store 8 ARGB
+      "st1         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
@@ -3713,17 +4494,15 @@
                      int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load 8 more
+      "1:          \n"
+      "ldp         q0, q1, [%0], #32             \n"  // load 8 ARGB
+      "ldp         q4, q5, [%1], #32             \n"  // load 8 more
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
-      "uqadd       v0.8b, v0.8b, v4.8b           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
-      "uqadd       v1.8b, v1.8b, v5.8b           \n"
       "prfm        pldl1keep, [%1, 448]          \n"
-      "uqadd       v2.8b, v2.8b, v6.8b           \n"
-      "uqadd       v3.8b, v3.8b, v7.8b           \n"
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"  // store 8 ARGB
+      "uqadd       v0.16b, v0.16b, v4.16b        \n"
+      "uqadd       v1.16b, v1.16b, v5.16b        \n"
+      "stp         q0, q1, [%2], #32             \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
@@ -3740,17 +4519,15 @@
                           int width) {
   asm volatile(
       // 8 pixel loop.
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // load 8 ARGB
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%1], #32 \n"  // load 8 more
+      "1:          \n"
+      "ldp         q0, q1, [%0], #32             \n"  // load 8 ARGB
+      "ldp         q4, q5, [%1], #32             \n"  // load 8 more
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
-      "uqsub       v0.8b, v0.8b, v4.8b           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
-      "uqsub       v1.8b, v1.8b, v5.8b           \n"
       "prfm        pldl1keep, [%1, 448]          \n"
-      "uqsub       v2.8b, v2.8b, v6.8b           \n"
-      "uqsub       v3.8b, v3.8b, v7.8b           \n"
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"  // store 8 ARGB
+      "uqsub       v0.16b, v0.16b, v4.16b        \n"
+      "uqsub       v1.16b, v1.16b, v5.16b        \n"
+      "stp         q0, q1, [%2], #32             \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_argb),   // %0
         "+r"(src_argb1),  // %1
@@ -3772,15 +4549,15 @@
   asm volatile(
       "movi        v3.8b, #255                   \n"  // alpha
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8b}, [%0], #8             \n"  // load 8 sobelx.
       "ld1         {v1.8b}, [%1], #8             \n"  // load 8 sobely.
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
       "uqadd       v0.8b, v0.8b, v1.8b           \n"  // add
       "prfm        pldl1keep, [%0, 448]          \n"
-      "orr         v1.8b, v0.8b, v0.8b           \n"
+      "mov         v1.8b, v0.8b                  \n"
       "prfm        pldl1keep, [%1, 448]          \n"
-      "orr         v2.8b, v0.8b, v0.8b           \n"
+      "mov         v2.8b, v0.8b                  \n"
       "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"  // store 8 ARGB
       "b.gt        1b                            \n"
       : "+r"(src_sobelx),  // %0
@@ -3798,7 +4575,7 @@
                           int width) {
   asm volatile(
       // 16 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load 16 sobelx.
       "ld1         {v1.16b}, [%1], #16           \n"  // load 16 sobely.
       "subs        %w3, %w3, #16                 \n"  // 16 processed per loop.
@@ -3827,7 +4604,7 @@
   asm volatile(
       "movi        v3.8b, #255                   \n"  // alpha
       // 8 pixel loop.
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v2.8b}, [%0], #8             \n"  // load 8 sobelx.
       "ld1         {v0.8b}, [%1], #8             \n"  // load 8 sobely.
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
@@ -3854,9 +4631,10 @@
                     uint8_t* dst_sobelx,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8b}, [%0],%5              \n"  // top
       "ld1         {v1.8b}, [%0],%6              \n"
+      "subs        %w4, %w4, #8                  \n"  // 8 pixels
       "usubl       v0.8h, v0.8b, v1.8b           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "ld1         {v2.8b}, [%1],%5              \n"  // center * 2
@@ -3867,7 +4645,6 @@
       "add         v0.8h, v0.8h, v1.8h           \n"
       "ld1         {v2.8b}, [%2],%5              \n"  // bottom
       "ld1         {v3.8b}, [%2],%6              \n"
-      "subs        %w4, %w4, #8                  \n"  // 8 pixels
       "prfm        pldl1keep, [%2, 448]          \n"
       "usubl       v1.8h, v2.8b, v3.8b           \n"
       "add         v0.8h, v0.8h, v1.8h           \n"
@@ -3895,9 +4672,10 @@
                     uint8_t* dst_sobely,
                     int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8b}, [%0],%4              \n"  // left
       "ld1         {v1.8b}, [%1],%4              \n"
+      "subs        %w3, %w3, #8                  \n"  // 8 pixels
       "usubl       v0.8h, v0.8b, v1.8b           \n"
       "ld1         {v2.8b}, [%0],%4              \n"  // center * 2
       "ld1         {v3.8b}, [%1],%4              \n"
@@ -3906,7 +4684,6 @@
       "add         v0.8h, v0.8h, v1.8h           \n"
       "ld1         {v2.8b}, [%0],%5              \n"  // right
       "ld1         {v3.8b}, [%1],%5              \n"
-      "subs        %w3, %w3, #8                  \n"  // 8 pixels
       "usubl       v1.8h, v2.8b, v3.8b           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "add         v0.8h, v0.8h, v1.8h           \n"
@@ -3925,55 +4702,38 @@
   );
 }
 
-// Caveat - rounds float to half float whereas scaling version truncates.
-void HalfFloat1Row_NEON(const uint16_t* src,
-                        uint16_t* dst,
-                        float /*unused*/,
-                        int width) {
-  asm volatile(
-      "1:                                        \n"
-      "ld1         {v1.16b}, [%0], #16           \n"  // load 8 shorts
-      "subs        %w2, %w2, #8                  \n"  // 8 pixels per loop
-      "uxtl        v2.4s, v1.4h                  \n"  // 8 int's
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "uxtl2       v3.4s, v1.8h                  \n"
-      "scvtf       v2.4s, v2.4s                  \n"  // 8 floats
-      "scvtf       v3.4s, v3.4s                  \n"
-      "fcvtn       v1.4h, v2.4s                  \n"  // 8 half floats
-      "fcvtn2      v1.8h, v3.4s                  \n"
-      "st1         {v1.16b}, [%1], #16           \n"  // store 8 shorts
-      "b.gt        1b                            \n"
-      : "+r"(src),   // %0
-        "+r"(dst),   // %1
-        "+r"(width)  // %2
-      :
-      : "cc", "memory", "v1", "v2", "v3");
-}
-
 void HalfFloatRow_NEON(const uint16_t* src,
                        uint16_t* dst,
                        float scale,
                        int width) {
   asm volatile(
-      "1:                                        \n"
-      "ld1         {v1.16b}, [%0], #16           \n"  // load 8 shorts
-      "subs        %w2, %w2, #8                  \n"  // 8 pixels per loop
-      "uxtl        v2.4s, v1.4h                  \n"  // 8 int's
+      "1:          \n"
+      "ldp         q0, q1, [%0], #32             \n"  // load 16 shorts
+      "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop
+      "uxtl        v2.4s, v0.4h                  \n"
+      "uxtl        v4.4s, v1.4h                  \n"
+      "uxtl2       v3.4s, v0.8h                  \n"
+      "uxtl2       v5.4s, v1.8h                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"
-      "uxtl2       v3.4s, v1.8h                  \n"
-      "scvtf       v2.4s, v2.4s                  \n"  // 8 floats
+      "scvtf       v2.4s, v2.4s                  \n"
+      "scvtf       v4.4s, v4.4s                  \n"
       "scvtf       v3.4s, v3.4s                  \n"
+      "scvtf       v5.4s, v5.4s                  \n"
       "fmul        v2.4s, v2.4s, %3.s[0]         \n"  // adjust exponent
+      "fmul        v4.4s, v4.4s, %3.s[0]         \n"
       "fmul        v3.4s, v3.4s, %3.s[0]         \n"
-      "uqshrn      v1.4h, v2.4s, #13             \n"  // isolate halffloat
-      "uqshrn2     v1.8h, v3.4s, #13             \n"
-      "st1         {v1.16b}, [%1], #16           \n"  // store 8 shorts
+      "fmul        v5.4s, v5.4s, %3.s[0]         \n"
+      "uqshrn      v0.4h, v2.4s, #13             \n"  // isolate halffloat
+      "uqshrn      v1.4h, v4.4s, #13             \n"
+      "uqshrn2     v0.8h, v3.4s, #13             \n"
+      "uqshrn2     v1.8h, v5.4s, #13             \n"
+      "stp         q0, q1, [%1], #32             \n"  // store 16 fp16
       "b.gt        1b                            \n"
       : "+r"(src),                      // %0
         "+r"(dst),                      // %1
         "+r"(width)                     // %2
       : "w"(scale * 1.9259299444e-34f)  // %3
-      : "cc", "memory", "v1", "v2", "v3");
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5");
 }
 
 void ByteToFloatRow_NEON(const uint8_t* src,
@@ -3981,7 +4741,7 @@
                          float scale,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.8b}, [%0], #8             \n"  // load 8 bytes
       "subs        %w2, %w2, #8                  \n"  // 8 pixels per loop
       "uxtl        v1.8h, v1.8b                  \n"  // 8 shorts
@@ -4006,7 +4766,7 @@
                                float* dst,
                                int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.8h}, [%0], #16            \n"  // load 8 halffloats
       "subs        %w2, %w2, #8                  \n"  // 8 floats per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -4030,7 +4790,7 @@
   asm volatile(
       "cmp         %w2, #8                       \n"  // Is there 8 rows?
       "b.lo        2f                            \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.h}[0], [%0], %3           \n"  // load 8 halffloats
       "ld1         {v0.h}[1], [%0], %3           \n"
       "ld1         {v0.h}[2], [%0], %3           \n"
@@ -4047,13 +4807,13 @@
       "b.gt        1b                            \n"
       "cmp         %w2, #1                       \n"  // Is there 1 value?
       "b.lo        3f                            \n"
-      "2:                                        \n"
+      "2:          \n"
       "ld1         {v1.h}[0], [%0], %3           \n"  // load 1 halffloats
       "subs        %w2, %w2, #1                  \n"  // 1 floats per loop
       "fcvtl       v2.4s, v1.4h                  \n"  // 1 floats
       "str         s2, [%1], #4                  \n"  // store 1 floats
       "b.gt        2b                            \n"
-      "3:                                        \n"
+      "3:          \n"
       : "+r"(src),                        // %0
         "+r"(dst),                        // %1
         "+r"(width)                       // %2
@@ -4066,7 +4826,7 @@
                                uint16_t* dst,  // fp16
                                int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q2, q3, [%0], #32             \n"  // load 8 floats
       "subs        %w2, %w2, #8                  \n"  // 8 floats per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -4090,7 +4850,7 @@
       "movi        v5.4s, #0                     \n"  // max
       "movi        v6.4s, #0                     \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.4s, v2.4s}, [%0], #32     \n"  // load 8 samples
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
       "fmul        v3.4s, v1.4s, %4.s[0]         \n"  // scale
@@ -4120,7 +4880,7 @@
       "movi        v5.4s, #0                     \n"  // max
       "movi        v6.4s, #0                     \n"  // max
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.4s, v2.4s}, [%0], #32     \n"  // load 8 samples
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
       "fmul        v3.4s, v1.4s, %4.s[0]         \n"  // scale
@@ -4144,10 +4904,10 @@
 
 void ScaleSamples_NEON(const float* src, float* dst, float scale, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.4s, v2.4s}, [%0], #32     \n"  // load 8 samples
-      "prfm        pldl1keep, [%0, 448]          \n"
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
+      "prfm        pldl1keep, [%0, 448]          \n"
       "fmul        v1.4s, v1.4s, %3.s[0]         \n"  // scale
       "fmul        v2.4s, v2.4s, %3.s[0]         \n"  // scale
       "st1         {v1.4s, v2.4s}, [%1], #32     \n"  // store 8 samples
@@ -4171,9 +4931,10 @@
       "movi        v6.8h, #4                     \n"  // constant 4
       "movi        v7.8h, #6                     \n"  // constant 6
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.8h}, [%0], #16            \n"  // load 8 samples, 5 rows
       "ld1         {v2.8h}, [%4], #16            \n"
+      "subs        %w6, %w6, #8                  \n"  // 8 processed per loop
       "uaddl       v0.4s, v1.4h, v2.4h           \n"  // * 1
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddl2      v1.4s, v1.8h, v2.8h           \n"  // * 1
@@ -4189,7 +4950,6 @@
       "umlal       v0.4s, v2.4h, v6.4h           \n"  // * 4
       "prfm        pldl1keep, [%3, 448]          \n"
       "umlal2      v1.4s, v2.8h, v6.8h           \n"  // * 4
-      "subs        %w6, %w6, #8                  \n"  // 8 processed per loop
       "st1         {v0.4s,v1.4s}, [%5], #32      \n"  // store 8 samples
       "prfm        pldl1keep, [%4, 448]          \n"
       "b.gt        1b                            \n"
@@ -4213,8 +4973,9 @@
       "movi        v6.4s, #4                     \n"  // constant 4
       "movi        v7.4s, #6                     \n"  // constant 6
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.4s,v1.4s,v2.4s}, [%0], %6 \n"  // load 12 source samples
+      "subs        %w5, %w5, #8                  \n"  // 8 processed per loop
       "add         v0.4s, v0.4s, v1.4s           \n"  // * 1
       "add         v1.4s, v1.4s, v2.4s           \n"  // * 1
       "ld1         {v2.4s,v3.4s}, [%2], #32      \n"
@@ -4227,7 +4988,6 @@
       "prfm        pldl1keep, [%0, 448]          \n"
       "mla         v0.4s, v2.4s, v6.4s           \n"  // * 4
       "mla         v1.4s, v3.4s, v6.4s           \n"  // * 4
-      "subs        %w5, %w5, #8                  \n"  // 8 processed per loop
       "uqrshrn     v0.4h, v0.4s, #8              \n"  // round and pack
       "uqrshrn2    v0.8h, v1.4s, #8              \n"
       "st1         {v0.8h}, [%4], #16            \n"  // store 8 samples
@@ -4255,9 +5015,10 @@
   asm volatile(
       "ld2r        {v6.4s, v7.4s}, [%7]          \n"  // constants 4 and 6
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.4s, v1.4s}, [%0], #32     \n"  // load 8 samples, 5 rows
       "ld1         {v2.4s, v3.4s}, [%1], #32     \n"
+      "subs        %w6, %w6, #8                  \n"  // 8 processed per loop
       "fmla        v0.4s, v2.4s, v6.4s           \n"  // * 4
       "ld1         {v4.4s, v5.4s}, [%2], #32     \n"
       "fmla        v1.4s, v3.4s, v6.4s           \n"
@@ -4274,7 +5035,6 @@
       "prfm        pldl1keep, [%3, 448]          \n"
       "fadd        v1.4s, v1.4s, v5.4s           \n"
       "prfm        pldl1keep, [%4, 448]          \n"
-      "subs        %w6, %w6, #8                  \n"  // 8 processed per loop
       "st1         {v0.4s, v1.4s}, [%5], #32     \n"  // store 8 samples
       "b.gt        1b                            \n"
       : "+r"(src0),               // %0
@@ -4293,9 +5053,10 @@
   asm volatile(
       "ld3r        {v6.4s, v7.4s, v8.4s}, [%3]   \n"  // constants 4, 6, 1/256
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.4s, v1.4s, v2.4s}, [%0], %4 \n"  // load 12 samples, 5
                                                         // rows
+      "subs        %w2, %w2, #8                  \n"    // 8 processed per loop
       "fadd        v0.4s, v0.4s, v1.4s           \n"    // * 1
       "ld1         {v4.4s, v5.4s}, [%0], %5      \n"
       "fadd        v1.4s, v1.4s, v2.4s           \n"
@@ -4310,7 +5071,6 @@
       "prfm        pldl1keep, [%0, 448]          \n"
       "fmul        v0.4s, v0.4s, v8.4s           \n"  // / 256
       "fmul        v1.4s, v1.4s, v8.4s           \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
       "st1         {v0.4s, v1.4s}, [%1], #32     \n"  // store 8 samples
       "b.gt        1b                            \n"
       : "+r"(src),                 // %0
@@ -4323,21 +5083,21 @@
       : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8");
 }
 
-#if LIBYUV_USE_ST3
+#if defined(LIBYUV_USE_ST3)
 // Convert biplanar NV21 to packed YUV24
 void NV21ToYUV24Row_NEON(const uint8_t* src_y,
                          const uint8_t* src_vu,
                          uint8_t* dst_yuv24,
                          int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v2.16b}, [%0], #16           \n"  // load 16 Y values
       "ld2         {v0.8b, v1.8b}, [%1], #16     \n"  // load 8 VU values
+      "subs        %w3, %w3, #16                 \n"  // 16 pixels per loop
       "zip1        v0.16b, v0.16b, v0.16b        \n"  // replicate V values
       "prfm        pldl1keep, [%0, 448]          \n"
       "zip1        v1.16b, v1.16b, v1.16b        \n"  // replicate U values
       "prfm        pldl1keep, [%1, 448]          \n"
-      "subs        %w3, %w3, #16                 \n"      // 16 pixels per loop
       "st3         {v0.16b,v1.16b,v2.16b}, [%2], #48 \n"  // store 16 YUV pixels
       "b.gt        1b                            \n"
       : "+r"(src_y),      // %0
@@ -4362,15 +5122,15 @@
                          int width) {
   asm volatile(
       "ld1         {v5.16b,v6.16b,v7.16b}, [%4]  \n"  // 3 shuffler constants
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"    // load 16 Y values
       "ld1         {v1.16b}, [%1], #16           \n"    // load 8 VU values
+      "subs        %w3, %w3, #16                 \n"    // 16 pixels per loop
       "tbl         v2.16b, {v0.16b,v1.16b}, v5.16b \n"  // weave into YUV24
       "prfm        pldl1keep, [%0, 448]          \n"
       "tbl         v3.16b, {v0.16b,v1.16b}, v6.16b \n"
       "prfm        pldl1keep, [%1, 448]          \n"
       "tbl         v4.16b, {v0.16b,v1.16b}, v7.16b \n"
-      "subs        %w3, %w3, #16                 \n"      // 16 pixels per loop
       "st1         {v2.16b,v3.16b,v4.16b}, [%2], #48 \n"  // store 16 YUV pixels
       "b.gt        1b                            \n"
       : "+r"(src_y),            // %0
@@ -4392,8 +5152,9 @@
   const uint8_t* src_ayuv_1 = src_ayuv + src_stride_ayuv;
   asm volatile(
 
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ayuv
+      "subs        %w3, %w3, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // V 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // U 16 bytes -> 8 shorts.
@@ -4403,7 +5164,6 @@
       "prfm        pldl1keep, [%1, 448]          \n"
       "uqrshrn     v3.8b, v0.8h, #2              \n"  // 2x2 average
       "uqrshrn     v2.8b, v1.8h, #2              \n"
-      "subs        %w3, %w3, #16                 \n"  // 16 processed per loop.
       "st2         {v2.8b,v3.8b}, [%2], #16      \n"  // store 8 pixels UV.
       "b.gt        1b                            \n"
       : "+r"(src_ayuv),    // %0
@@ -4421,8 +5181,9 @@
   const uint8_t* src_ayuv_1 = src_ayuv + src_stride_ayuv;
   asm volatile(
 
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ayuv
+      "subs        %w3, %w3, #16                 \n"  // 16 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // V 16 bytes -> 8 shorts.
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"  // U 16 bytes -> 8 shorts.
@@ -4432,7 +5193,6 @@
       "prfm        pldl1keep, [%1, 448]          \n"
       "uqrshrn     v0.8b, v0.8h, #2              \n"  // 2x2 average
       "uqrshrn     v1.8b, v1.8h, #2              \n"
-      "subs        %w3, %w3, #16                 \n"  // 16 processed per loop.
       "st2         {v0.8b,v1.8b}, [%2], #16      \n"  // store 8 pixels VU.
       "b.gt        1b                            \n"
       : "+r"(src_ayuv),    // %0
@@ -4446,7 +5206,7 @@
 // Copy row of AYUV Y's into Y
 void AYUVToYRow_NEON(const uint8_t* src_ayuv, uint8_t* dst_y, int width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16
       "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop
       "prfm        pldl1keep, [%0, 448]          \n"
@@ -4459,28 +5219,23 @@
       : "cc", "memory", "v0", "v1", "v2", "v3");
 }
 
-// Shuffle table for swapping UV bytes.
-static const uvec8 kShuffleSwapUV = {1u, 0u, 3u,  2u,  5u,  4u,  7u,  6u,
-                                     9u, 8u, 11u, 10u, 13u, 12u, 15u, 14u};
-
 // Convert UV plane of NV12 to VU of NV21.
 void SwapUVRow_NEON(const uint8_t* src_uv, uint8_t* dst_vu, int width) {
   asm volatile(
-      "ld1         {v2.16b}, [%3]                \n"  // shuffler
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], 16            \n"  // load 16 UV values
       "ld1         {v1.16b}, [%0], 16            \n"
       "subs        %w2, %w2, #16                 \n"  // 16 pixels per loop
-      "tbl         v0.16b, {v0.16b}, v2.16b      \n"
+      "rev16       v0.16b, v0.16b                \n"
       "prfm        pldl1keep, [%0, 448]          \n"
-      "tbl         v1.16b, {v1.16b}, v2.16b      \n"
+      "rev16       v1.16b, v1.16b                \n"
       "stp         q0, q1, [%1], 32              \n"  // store 16 VU pixels
       "b.gt        1b                            \n"
-      : "+r"(src_uv),         // %0
-        "+r"(dst_vu),         // %1
-        "+r"(width)           // %2
-      : "r"(&kShuffleSwapUV)  // %3
-      : "cc", "memory", "v0", "v1", "v2");
+      : "+r"(src_uv),  // %0
+        "+r"(dst_vu),  // %1
+        "+r"(width)    // %2
+      :
+      : "cc", "memory", "v0", "v1");
 }
 
 void HalfMergeUVRow_NEON(const uint8_t* src_u,
@@ -4492,11 +5247,12 @@
   const uint8_t* src_u_1 = src_u + src_stride_u;
   const uint8_t* src_v_1 = src_v + src_stride_v;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b}, [%0], #16           \n"  // load 16 U values
       "ld1         {v1.16b}, [%2], #16           \n"  // load 16 V values
       "ld1         {v2.16b}, [%1], #16           \n"
       "ld1         {v3.16b}, [%3], #16           \n"
+      "subs        %w5, %w5, #16                 \n"  // 16 src pixels per loop
       "uaddlp      v0.8h, v0.16b                 \n"  // half size
       "prfm        pldl1keep, [%0, 448]          \n"
       "uaddlp      v1.8h, v1.16b                 \n"
@@ -4507,7 +5263,6 @@
       "prfm        pldl1keep, [%3, 448]          \n"
       "uqrshrn     v0.8b, v0.8h, #2              \n"
       "uqrshrn     v1.8b, v1.8h, #2              \n"
-      "subs        %w5, %w5, #16                 \n"  // 16 src pixels per loop
       "st2         {v0.8b, v1.8b}, [%4], #16     \n"  // store 8 UV pixels
       "b.gt        1b                            \n"
       : "+r"(src_u),    // %0
@@ -4528,7 +5283,7 @@
   int shift = depth - 16;  // Negative for right shift.
   asm volatile(
       "dup         v2.8h, %w4                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.8h, v1.8h}, [%0], #32     \n"  // load 8 UV
       "subs        %w3, %w3, #8                  \n"  // 8 src pixels per loop
       "ushl        v0.8h, v0.8h, v2.8h           \n"
@@ -4551,13 +5306,13 @@
                          int width) {
   asm volatile(
       "dup         v2.8h, %w3                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"
+      "subs        %w2, %w2, #16                 \n"  // 16 src pixels per loop
       "mul         v0.8h, v0.8h, v2.8h           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
       "mul         v1.8h, v1.8h, v2.8h           \n"
       "stp         q0, q1, [%1], #32             \n"  // store 16 pixels
-      "subs        %w2, %w2, #16                 \n"  // 16 src pixels per loop
       "b.gt        1b                            \n"
       : "+r"(src_y),  // %0
         "+r"(dst_y),  // %1
@@ -4572,19 +5327,17 @@
                        int width) {
   asm volatile(
       "dup         v4.8h, %w3                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q2, q3, [%0], #32             \n"
+      "subs        %w2, %w2, #16                 \n"  // 16 src pixels per loop
       "umull       v0.4s, v2.4h, v4.4h           \n"
       "umull2      v1.4s, v2.8h, v4.8h           \n"
       "umull       v2.4s, v3.4h, v4.4h           \n"
       "umull2      v3.4s, v3.8h, v4.8h           \n"
       "prfm        pldl1keep, [%0, 448]          \n"
-      "shrn        v0.4h, v0.4s, #16             \n"
-      "shrn2       v0.8h, v1.4s, #16             \n"
-      "shrn        v1.4h, v2.4s, #16             \n"
-      "shrn2       v1.8h, v3.4s, #16             \n"
+      "uzp2        v0.8h, v0.8h, v1.8h           \n"
+      "uzp2        v1.8h, v2.8h, v3.8h           \n"
       "stp         q0, q1, [%1], #32             \n"  // store 16 pixels
-      "subs        %w2, %w2, #16                 \n"  // 16 src pixels per loop
       "b.gt        1b                            \n"
       : "+r"(src_y),  // %0
         "+r"(dst_y),  // %1
@@ -4602,17 +5355,19 @@
                           uint8_t* dst_y,
                           int scale,
                           int width) {
-  int shift = 15 - __builtin_clz((int32_t)scale);  // Negative shl is shr
+  // 15 - clz(scale), + 8 to shift result into the high half of the lane to
+  // saturate, then we can just use UZP2 to narrow rather than a pair of
+  // saturating narrow instructions.
+  int shift = 23 - __builtin_clz((int32_t)scale);
   asm volatile(
       "dup         v2.8h, %w3                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ldp         q0, q1, [%0], #32             \n"
-      "ushl        v0.8h, v0.8h, v2.8h           \n"  // shr = v2 is negative
-      "ushl        v1.8h, v1.8h, v2.8h           \n"
-      "prfm        pldl1keep, [%0, 448]          \n"
-      "uqxtn       v0.8b, v0.8h                  \n"
-      "uqxtn2      v0.16b, v1.8h                 \n"
       "subs        %w2, %w2, #16                 \n"  // 16 src pixels per loop
+      "uqshl       v0.8h, v0.8h, v2.8h           \n"
+      "uqshl       v1.8h, v1.8h, v2.8h           \n"
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uzp2        v0.16b, v0.16b, v1.16b        \n"
       "str         q0, [%1], #16                 \n"  // store 16 pixels
       "b.gt        1b                            \n"
       : "+r"(src_y),  // %0
@@ -4622,6 +5377,40 @@
       : "cc", "memory", "v0", "v1", "v2");
 }
 
+// Use scale to convert J420 to I420
+// scale parameter is 8.8 fixed point but limited to 0 to 255
+// Function is based on DivideRow, but adds a bias
+// Does not clamp
+void Convert8To8Row_NEON(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width) {
+  asm volatile(
+      "dup         v4.16b, %w3                   \n"  // scale
+      "dup         v5.16b, %w4                   \n"  // bias
+      "1:          \n"
+      "ldp         q2, q3, [%0], #32             \n"
+      "subs        %w2, %w2, #32                 \n"  // 32 pixels per loop
+      "umull       v0.8h, v2.8b, v4.8b           \n"
+      "umull2      v1.8h, v2.16b, v4.16b         \n"
+      "umull       v2.8h, v3.8b, v4.8b           \n"
+      "umull2      v3.8h, v3.16b, v4.16b         \n"
+      "prfm        pldl1keep, [%0, 448]          \n"
+      "uzp2        v0.16b, v0.16b, v1.16b        \n"
+      "uzp2        v1.16b, v2.16b, v3.16b        \n"
+      "add         v0.16b, v0.16b, v5.16b        \n"  // add bias (16)
+      "add         v1.16b, v1.16b, v5.16b        \n"
+      "stp         q0, q1, [%1], #32             \n"  // store 32 pixels
+      "b.gt        1b                            \n"
+      : "+r"(src_y),  // %0
+        "+r"(dst_y),  // %1
+        "+r"(width)   // %2
+      : "r"(scale),   // %3
+        "r"(bias)     // %4
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5");
+}
+
 #endif  // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__)
 
 #ifdef __cplusplus
diff --git a/source/row_rvv.cc b/source/row_rvv.cc
index 0bf2bef..07606d7 100644
--- a/source/row_rvv.cc
+++ b/source/row_rvv.cc
@@ -28,6 +28,20 @@
 extern "C" {
 #endif
 
+#ifdef LIBYUV_RVV_HAS_VXRM_ARG
+// Fill YUV -> RGB conversion constants into vectors
+#define YUVTORGB_SETUP(yuvconst, ub, vr, ug, vg, yg, bb, bg, br) \
+  {                                                              \
+    ub = yuvconst->kUVCoeff[0];                                  \
+    vr = yuvconst->kUVCoeff[1];                                  \
+    ug = yuvconst->kUVCoeff[2];                                  \
+    vg = yuvconst->kUVCoeff[3];                                  \
+    yg = yuvconst->kRGBCoeffBias[0];                             \
+    bb = yuvconst->kRGBCoeffBias[1] + 32;                        \
+    bg = yuvconst->kRGBCoeffBias[2] - 32;                        \
+    br = yuvconst->kRGBCoeffBias[3] + 32;                        \
+  }
+#else
 // Fill YUV -> RGB conversion constants into vectors
 // NOTE: To match behavior on other platforms, vxrm (fixed-point rounding mode
 // register) is set to round-to-nearest-up mode(0).
@@ -43,7 +57,7 @@
     bg = yuvconst->kRGBCoeffBias[2] - 32;                        \
     br = yuvconst->kRGBCoeffBias[3] + 32;                        \
   }
-
+#endif
 // Read [2*VLEN/8] Y, [VLEN/8] U and [VLEN/8] V from 422
 #define READYUV422(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16) \
   {                                                              \
@@ -95,6 +109,15 @@
     v_r_16 = __riscv_vssubu_vx_u16m4(v_tmp2, br, vl);                          \
   }
 
+#ifdef LIBYUV_RVV_HAS_VXRM_ARG
+// Convert from fixed point RGB To 8 bit RGB
+#define RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r)        \
+  {                                                                 \
+    v_g = __riscv_vnclipu_wx_u8m2(v_g_16, 6, __RISCV_VXRM_RNU, vl); \
+    v_b = __riscv_vnclipu_wx_u8m2(v_b_16, 6, __RISCV_VXRM_RNU, vl); \
+    v_r = __riscv_vnclipu_wx_u8m2(v_r_16, 6, __RISCV_VXRM_RNU, vl); \
+  }
+#else
 // Convert from fixed point RGB To 8 bit RGB
 #define RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r) \
   {                                                          \
@@ -102,7 +125,53 @@
     v_b = __riscv_vnclipu_wx_u8m2(v_b_16, 6, vl);            \
     v_r = __riscv_vnclipu_wx_u8m2(v_r_16, 6, vl);            \
   }
+#endif
 
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+// Read [2*VLEN/8] Y from src_y; Read [VLEN/8] U and [VLEN/8] V from src_uv
+#define READNV12(vl, w, src_y, src_uv, v_u, v_v, v_y_16) \
+  {                                                      \
+    vuint8m1x2_t v_tmp;                                  \
+    vuint8m1_t v_tmp0, v_tmp1;                           \
+    vuint8m2_t v_y;                                      \
+    vuint16m2_t v_u_16, v_v_16;                          \
+    vl = __riscv_vsetvl_e8m1((w + 1) / 2);               \
+    v_tmp = __riscv_vlseg2e8_v_u8m1x2(src_uv, vl);       \
+    v_tmp0 = __riscv_vget_v_u8m1x2_u8m1(v_tmp, 0);       \
+    v_tmp1 = __riscv_vget_v_u8m1x2_u8m1(v_tmp, 1);       \
+    v_u_16 = __riscv_vwaddu_vx_u16m2(v_tmp0, 0, vl);     \
+    v_v_16 = __riscv_vwaddu_vx_u16m2(v_tmp1, 0, vl);     \
+    v_v_16 = __riscv_vmul_vx_u16m2(v_v_16, 0x0101, vl);  \
+    v_u_16 = __riscv_vmul_vx_u16m2(v_u_16, 0x0101, vl);  \
+    v_v = __riscv_vreinterpret_v_u16m2_u8m2(v_v_16);     \
+    v_u = __riscv_vreinterpret_v_u16m2_u8m2(v_u_16);     \
+    vl = __riscv_vsetvl_e8m2(w);                         \
+    v_y = __riscv_vle8_v_u8m2(src_y, vl);                \
+    v_y_16 = __riscv_vwaddu_vx_u16m4(v_y, 0, vl);        \
+  }
+
+// Read 2*[VLEN/8] Y from src_y; Read [VLEN/8] U and [VLEN/8] V from src_vu
+#define READNV21(vl, w, src_y, src_vu, v_u, v_v, v_y_16) \
+  {                                                      \
+    vuint8m1x2_t v_tmp;                                  \
+    vuint8m1_t v_tmp0, v_tmp1;                           \
+    vuint8m2_t v_y;                                      \
+    vuint16m2_t v_u_16, v_v_16;                          \
+    vl = __riscv_vsetvl_e8m1((w + 1) / 2);               \
+    v_tmp = __riscv_vlseg2e8_v_u8m1x2(src_vu, vl);       \
+    v_tmp0 = __riscv_vget_v_u8m1x2_u8m1(v_tmp, 0);       \
+    v_tmp1 = __riscv_vget_v_u8m1x2_u8m1(v_tmp, 1);       \
+    v_u_16 = __riscv_vwaddu_vx_u16m2(v_tmp1, 0, vl);     \
+    v_v_16 = __riscv_vwaddu_vx_u16m2(v_tmp0, 0, vl);     \
+    v_v_16 = __riscv_vmul_vx_u16m2(v_v_16, 0x0101, vl);  \
+    v_u_16 = __riscv_vmul_vx_u16m2(v_u_16, 0x0101, vl);  \
+    v_v = __riscv_vreinterpret_v_u16m2_u8m2(v_v_16);     \
+    v_u = __riscv_vreinterpret_v_u16m2_u8m2(v_u_16);     \
+    vl = __riscv_vsetvl_e8m2(w);                         \
+    v_y = __riscv_vle8_v_u8m2(src_y, vl);                \
+    v_y_16 = __riscv_vwaddu_vx_u16m4(v_y, 0, vl);        \
+  }
+#else
 // Read [2*VLEN/8] Y from src_y; Read [VLEN/8] U and [VLEN/8] V from src_uv
 #define READNV12(vl, w, src_y, src_uv, v_u, v_v, v_y_16)   \
   {                                                        \
@@ -140,6 +209,7 @@
     v_y = __riscv_vle8_v_u8m2(src_y, vl);                  \
     v_y_16 = __riscv_vwaddu_vx_u16m4(v_y, 0, vl);          \
   }
+#endif
 
 #ifdef HAS_ARGBTOAR64ROW_RVV
 void ARGBToAR64Row_RVV(const uint8_t* src_argb, uint16_t* dst_ar64, int width) {
@@ -160,6 +230,34 @@
 #endif
 
 #ifdef HAS_ARGBTOAB64ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToAB64Row_RVV(const uint8_t* src_argb, uint16_t* dst_ab64, int width) {
+  size_t avl = (size_t)width;
+  do {
+    vuint16m2x4_t v_dst_ab64;
+    vuint16m2_t v_b_16, v_g_16, v_r_16, v_a_16;
+    size_t vl = __riscv_vsetvl_e8m1(avl);
+    vuint8m1x4_t v_src_argb = __riscv_vlseg4e8_v_u8m1x4(src_argb, vl);
+    vuint8m1_t v_b = __riscv_vget_v_u8m1x4_u8m1(v_src_argb, 0);
+    vuint8m1_t v_g = __riscv_vget_v_u8m1x4_u8m1(v_src_argb, 1);
+    vuint8m1_t v_r = __riscv_vget_v_u8m1x4_u8m1(v_src_argb, 2);
+    vuint8m1_t v_a = __riscv_vget_v_u8m1x4_u8m1(v_src_argb, 3);
+    v_b_16 = __riscv_vwaddu_vx_u16m2(v_b, 0, vl);
+    v_g_16 = __riscv_vwaddu_vx_u16m2(v_g, 0, vl);
+    v_r_16 = __riscv_vwaddu_vx_u16m2(v_r, 0, vl);
+    v_a_16 = __riscv_vwaddu_vx_u16m2(v_a, 0, vl);
+    v_b_16 = __riscv_vmul_vx_u16m2(v_b_16, 0x0101, vl);
+    v_g_16 = __riscv_vmul_vx_u16m2(v_g_16, 0x0101, vl);
+    v_r_16 = __riscv_vmul_vx_u16m2(v_r_16, 0x0101, vl);
+    v_a_16 = __riscv_vmul_vx_u16m2(v_a_16, 0x0101, vl);
+    v_dst_ab64 = __riscv_vcreate_v_u16m2x4(v_r_16, v_g_16, v_b_16, v_a_16);
+    __riscv_vsseg4e16_v_u16m2x4(dst_ab64, v_dst_ab64, vl);
+    avl -= vl;
+    src_argb += 4 * vl;
+    dst_ab64 += 4 * vl;
+  } while (avl > 0);
+}
+#else
 void ARGBToAB64Row_RVV(const uint8_t* src_argb, uint16_t* dst_ab64, int width) {
   size_t avl = (size_t)width;
   do {
@@ -182,6 +280,7 @@
   } while (avl > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_AR64TOARGBROW_RVV
 void AR64ToARGBRow_RVV(const uint16_t* src_ar64, uint8_t* dst_argb, int width) {
@@ -201,6 +300,26 @@
 #endif
 
 #ifdef HAS_AR64TOAB64ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void AR64ToAB64Row_RVV(const uint16_t* src_ar64,
+                       uint16_t* dst_ab64,
+                       int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e16m2(w);
+    vuint16m2x4_t v_argb16 = __riscv_vlseg4e16_v_u16m2x4(src_ar64, vl);
+    vuint16m2_t v_b = __riscv_vget_v_u16m2x4_u16m2(v_argb16, 0);
+    vuint16m2_t v_g = __riscv_vget_v_u16m2x4_u16m2(v_argb16, 1);
+    vuint16m2_t v_r = __riscv_vget_v_u16m2x4_u16m2(v_argb16, 2);
+    vuint16m2_t v_a = __riscv_vget_v_u16m2x4_u16m2(v_argb16, 3);
+    vuint16m2x4_t v_dst_abgr = __riscv_vcreate_v_u16m2x4(v_r, v_g, v_b, v_a);
+    __riscv_vsseg4e16_v_u16m2x4(dst_ab64, v_dst_abgr, vl);
+    w -= vl;
+    src_ar64 += vl * 4;
+    dst_ab64 += vl * 4;
+  } while (w > 0);
+}
+#else
 void AR64ToAB64Row_RVV(const uint16_t* src_ar64,
                        uint16_t* dst_ab64,
                        int width) {
@@ -216,8 +335,31 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_AB64TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void AB64ToARGBRow_RVV(const uint16_t* src_ab64, uint8_t* dst_argb, int width) {
+  size_t avl = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e16m2(avl);
+    vuint16m2x4_t v_abgr16 = __riscv_vlseg4e16_v_u16m2x4(src_ab64, vl);
+    vuint16m2_t v_r_16 = __riscv_vget_v_u16m2x4_u16m2(v_abgr16, 0);
+    vuint16m2_t v_g_16 = __riscv_vget_v_u16m2x4_u16m2(v_abgr16, 1);
+    vuint16m2_t v_b_16 = __riscv_vget_v_u16m2x4_u16m2(v_abgr16, 2);
+    vuint16m2_t v_a_16 = __riscv_vget_v_u16m2x4_u16m2(v_abgr16, 3);
+    vuint8m1_t v_b = __riscv_vnsrl_wx_u8m1(v_b_16, 8, vl);
+    vuint8m1_t v_g = __riscv_vnsrl_wx_u8m1(v_g_16, 8, vl);
+    vuint8m1_t v_r = __riscv_vnsrl_wx_u8m1(v_r_16, 8, vl);
+    vuint8m1_t v_a = __riscv_vnsrl_wx_u8m1(v_a_16, 8, vl);
+    vuint8m1x4_t v_dst_argb = __riscv_vcreate_v_u8m1x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m1x4(dst_argb, v_dst_argb, vl);
+    avl -= vl;
+    src_ab64 += 4 * vl;
+    dst_argb += 4 * vl;
+  } while (avl > 0);
+}
+#else
 void AB64ToARGBRow_RVV(const uint16_t* src_ab64, uint8_t* dst_argb, int width) {
   size_t avl = (size_t)width;
   do {
@@ -236,8 +378,28 @@
   } while (avl > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RAWTOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void RAWToARGBRow_RVV(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    vuint8m2x3_t v_bgr = __riscv_vlseg3e8_v_u8m2x3(src_raw, vl);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 1);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 2);
+    vuint8m2x4_t v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_raw += vl * 3;
+    dst_argb += vl * 4;
+    vl = __riscv_vsetvl_e8m2(w);
+  } while (w > 0);
+}
+#else
 void RAWToARGBRow_RVV(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
   size_t w = (size_t)width;
   size_t vl = __riscv_vsetvl_e8m2(w);
@@ -253,8 +415,28 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RAWTORGBAROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void RAWToRGBARow_RVV(const uint8_t* src_raw, uint8_t* dst_rgba, int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    vuint8m2x3_t v_bgr = __riscv_vlseg3e8_v_u8m2x3(src_raw, vl);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 1);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 2);
+    vuint8m2x4_t v_dst_rgba = __riscv_vcreate_v_u8m2x4(v_a, v_b, v_g, v_r);
+    __riscv_vsseg4e8_v_u8m2x4(dst_rgba, v_dst_rgba, vl);
+    w -= vl;
+    src_raw += vl * 3;
+    dst_rgba += vl * 4;
+    vl = __riscv_vsetvl_e8m2(w);
+  } while (w > 0);
+}
+#else
 void RAWToRGBARow_RVV(const uint8_t* src_raw, uint8_t* dst_rgba, int width) {
   size_t w = (size_t)width;
   size_t vl = __riscv_vsetvl_e8m2(w);
@@ -270,8 +452,26 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RAWTORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void RAWToRGB24Row_RVV(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x3_t v_bgr = __riscv_vlseg3e8_v_u8m2x3(src_raw, vl);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 1);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_bgr, 2);
+    vuint8m2x3_t v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_raw += vl * 3;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void RAWToRGB24Row_RVV(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) {
   size_t w = (size_t)width;
   do {
@@ -285,8 +485,26 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTORAWROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToRAWRow_RVV(const uint8_t* src_argb, uint8_t* dst_raw, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2x3_t v_dst_bgr = __riscv_vcreate_v_u8m2x3(v_r, v_g, v_b);
+    __riscv_vsseg3e8_v_u8m2x3(dst_raw, v_dst_bgr, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_raw += vl * 3;
+  } while (w > 0);
+}
+#else
 void ARGBToRAWRow_RVV(const uint8_t* src_argb, uint8_t* dst_raw, int width) {
   size_t w = (size_t)width;
   do {
@@ -300,8 +518,28 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToRGB24Row_RVV(const uint8_t* src_argb,
+                        uint8_t* dst_rgb24,
+                        int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2x3_t v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void ARGBToRGB24Row_RVV(const uint8_t* src_argb,
                         uint8_t* dst_rgb24,
                         int width) {
@@ -317,8 +555,27 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTOABGRROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToABGRRow_RVV(const uint8_t* src_argb, uint8_t* dst_abgr, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 3);
+    vuint8m2x4_t v_dst_abgr = __riscv_vcreate_v_u8m2x4(v_r, v_g, v_b, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_abgr, v_dst_abgr, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_abgr += vl * 4;
+  } while (w > 0);
+}
+#else
 void ARGBToABGRRow_RVV(const uint8_t* src_argb, uint8_t* dst_abgr, int width) {
   size_t w = (size_t)width;
   do {
@@ -332,8 +589,27 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTOBGRAROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToBGRARow_RVV(const uint8_t* src_argb, uint8_t* dst_bgra, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 3);
+    vuint8m2x4_t v_dst_bgra = __riscv_vcreate_v_u8m2x4(v_a, v_r, v_g, v_b);
+    __riscv_vsseg4e8_v_u8m2x4(dst_bgra, v_dst_bgra, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_bgra += vl * 4;
+  } while (w > 0);
+}
+#else
 void ARGBToBGRARow_RVV(const uint8_t* src_argb, uint8_t* dst_bgra, int width) {
   size_t w = (size_t)width;
   do {
@@ -347,8 +623,27 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTORGBAROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBToRGBARow_RVV(const uint8_t* src_argb, uint8_t* dst_rgba, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 3);
+    vuint8m2x4_t v_dst_rgba = __riscv_vcreate_v_u8m2x4(v_a, v_b, v_g, v_r);
+    __riscv_vsseg4e8_v_u8m2x4(dst_rgba, v_dst_rgba, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_rgba += vl * 4;
+  } while (w > 0);
+}
+#else
 void ARGBToRGBARow_RVV(const uint8_t* src_argb, uint8_t* dst_rgba, int width) {
   size_t w = (size_t)width;
   do {
@@ -362,8 +657,27 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RGBATOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void RGBAToARGBRow_RVV(const uint8_t* src_rgba, uint8_t* dst_argb, int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_rgba = __riscv_vlseg4e8_v_u8m2x4(src_rgba, vl);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 0);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 1);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 2);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 3);
+    vuint8m2x4_t v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_rgba += vl * 4;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void RGBAToARGBRow_RVV(const uint8_t* src_rgba, uint8_t* dst_argb, int width) {
   size_t w = (size_t)width;
   do {
@@ -377,8 +691,30 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RGB24TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void RGB24ToARGBRow_RVV(const uint8_t* src_rgb24,
+                        uint8_t* dst_argb,
+                        int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    vuint8m2x3_t v_src_rgb = __riscv_vlseg3e8_v_u8m2x3(src_rgb24, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 2);
+    vuint8m2x4_t v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_rgb24 += vl * 3;
+    dst_argb += vl * 4;
+    vl = __riscv_vsetvl_e8m2(w);
+  } while (w > 0);
+}
+#else
 void RGB24ToARGBRow_RVV(const uint8_t* src_rgb24,
                         uint8_t* dst_argb,
                         int width) {
@@ -396,8 +732,41 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I444TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I444ToARGBRow_RVV(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  vuint8m2x4_t v_dst_argb;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    READYUV444(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_u += vl;
+    src_v += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void I444ToARGBRow_RVV(const uint8_t* src_y,
                        const uint8_t* src_u,
                        const uint8_t* src_v,
@@ -427,8 +796,43 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I444ALPHATOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I444AlphaToARGBRow_RVV(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            const uint8_t* src_a,
+                            uint8_t* dst_argb,
+                            const struct YuvConstants* yuvconstants,
+                            int width) {
+  size_t vl;
+  size_t w = (size_t)width;
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    vuint8m2x4_t v_dst_argb;
+    READYUV444(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    v_a = __riscv_vle8_v_u8m2(src_a, vl);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_a += vl;
+    src_u += vl;
+    src_v += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void I444AlphaToARGBRow_RVV(const uint8_t* src_y,
                             const uint8_t* src_u,
                             const uint8_t* src_v,
@@ -460,8 +864,40 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I444TORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I444ToRGB24Row_RVV(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  size_t vl;
+  size_t w = (size_t)width;
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    vuint8m2x3_t v_dst_rgb;
+    READYUV444(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_y += vl;
+    src_u += vl;
+    src_v += vl;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void I444ToRGB24Row_RVV(const uint8_t* src_y,
                         const uint8_t* src_u,
                         const uint8_t* src_v,
@@ -490,8 +926,41 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I422TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I422ToARGBRow_RVV(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  vuint8m2x4_t v_dst_argb;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    READYUV422(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_u += vl / 2;
+    src_v += vl / 2;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void I422ToARGBRow_RVV(const uint8_t* src_y,
                        const uint8_t* src_u,
                        const uint8_t* src_v,
@@ -521,8 +990,43 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I422ALPHATOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I422AlphaToARGBRow_RVV(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            const uint8_t* src_a,
+                            uint8_t* dst_argb,
+                            const struct YuvConstants* yuvconstants,
+                            int width) {
+  size_t vl;
+  size_t w = (size_t)width;
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    vuint8m2x4_t v_dst_argb;
+    READYUV422(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    v_a = __riscv_vle8_v_u8m2(src_a, vl);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_a += vl;
+    src_u += vl / 2;
+    src_v += vl / 2;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void I422AlphaToARGBRow_RVV(const uint8_t* src_y,
                             const uint8_t* src_u,
                             const uint8_t* src_v,
@@ -554,8 +1058,41 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I422TORGBAROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I422ToRGBARow_RVV(const uint8_t* src_y,
+                       const uint8_t* src_u,
+                       const uint8_t* src_v,
+                       uint8_t* dst_rgba,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  vuint8m2x4_t v_dst_rgba;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    READYUV422(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_rgba = __riscv_vcreate_v_u8m2x4(v_a, v_b, v_g, v_r);
+    __riscv_vsseg4e8_v_u8m2x4(dst_rgba, v_dst_rgba, vl);
+    w -= vl;
+    src_y += vl;
+    src_u += vl / 2;
+    src_v += vl / 2;
+    dst_rgba += vl * 4;
+  } while (w > 0);
+}
+#else
 void I422ToRGBARow_RVV(const uint8_t* src_y,
                        const uint8_t* src_u,
                        const uint8_t* src_v,
@@ -585,8 +1122,40 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I422TORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void I422ToRGB24Row_RVV(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  size_t vl;
+  size_t w = (size_t)width;
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  vuint8m2x3_t v_dst_rgb;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    READYUV422(vl, w, src_y, src_u, src_v, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_y += vl;
+    src_u += vl / 2;
+    src_v += vl / 2;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void I422ToRGB24Row_RVV(const uint8_t* src_y,
                         const uint8_t* src_u,
                         const uint8_t* src_v,
@@ -615,8 +1184,48 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_I400TOARGBROW_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void I400ToARGBRow_RVV(const uint8_t* src_y,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  const bool is_yb_positive = (yuvconstants->kRGBCoeffBias[4] >= 0);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  vuint16m4_t v_yg = __riscv_vmv_v_x_u16m4(yuvconstants->kRGBCoeffBias[0], vl);
+  vuint8m2x4_t v_dst_argb;
+  vuint16m4_t v_yb;
+  if (is_yb_positive) {
+    v_yb = __riscv_vmv_v_x_u16m4(yuvconstants->kRGBCoeffBias[4] - 32, vl);
+  } else {
+    v_yb = __riscv_vmv_v_x_u16m4(-yuvconstants->kRGBCoeffBias[4] + 32, vl);
+  }
+  do {
+    vuint8m2_t v_y, v_out;
+    vuint16m4_t v_y_16, v_tmp0, v_tmp1, v_tmp2;
+    vl = __riscv_vsetvl_e8m2(w);
+    v_y = __riscv_vle8_v_u8m2(src_y, vl);
+    v_y_16 = __riscv_vwaddu_vx_u16m4(v_y, 0, vl);
+    v_tmp0 = __riscv_vmul_vx_u16m4(v_y_16, 0x0101, vl);  // 257 * v_y
+    v_tmp1 = __riscv_vmulhu_vv_u16m4(v_tmp0, v_yg, vl);
+    if (is_yb_positive) {
+      v_tmp2 = __riscv_vsaddu_vv_u16m4(v_tmp1, v_yb, vl);
+    } else {
+      v_tmp2 = __riscv_vssubu_vv_u16m4(v_tmp1, v_yb, vl);
+    }
+    v_out = __riscv_vnclipu_wx_u8m2(v_tmp2, 6, __RISCV_VXRM_RNU, vl);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_out, v_out, v_out, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void I400ToARGBRow_RVV(const uint8_t* src_y,
                        uint8_t* dst_argb,
                        const struct YuvConstants* yuvconstants,
@@ -656,8 +1265,25 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_J400TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void J400ToARGBRow_RVV(const uint8_t* src_y, uint8_t* dst_argb, int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    vuint8m2_t v_y = __riscv_vle8_v_u8m2(src_y, vl);
+    vuint8m2x4_t v_dst_argb = __riscv_vcreate_v_u8m2x4(v_y, v_y, v_y, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    dst_argb += vl * 4;
+    vl = __riscv_vsetvl_e8m2(w);
+  } while (w > 0);
+}
+#else
 void J400ToARGBRow_RVV(const uint8_t* src_y, uint8_t* dst_argb, int width) {
   size_t w = (size_t)width;
   size_t vl = __riscv_vsetvl_e8m2(w);
@@ -673,6 +1299,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_COPYROW_RVV
 void CopyRow_RVV(const uint8_t* src, uint8_t* dst, int width) {
@@ -689,6 +1316,36 @@
 #endif
 
 #ifdef HAS_NV12TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void NV12ToARGBRow_RVV(const uint8_t* src_y,
+                       const uint8_t* src_uv,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  vuint8m2x4_t v_dst_argb;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    READNV12(vl, w, src_y, src_uv, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_uv += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void NV12ToARGBRow_RVV(const uint8_t* src_y,
                        const uint8_t* src_uv,
                        uint8_t* dst_argb,
@@ -716,8 +1373,38 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_NV12TORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void NV12ToRGB24Row_RVV(const uint8_t* src_y,
+                        const uint8_t* src_uv,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r;
+  vuint8m2x3_t v_dst_rgb;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    READNV12(vl, w, src_y, src_uv, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_y += vl;
+    src_uv += vl;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void NV12ToRGB24Row_RVV(const uint8_t* src_y,
                         const uint8_t* src_uv,
                         uint8_t* dst_rgb24,
@@ -744,8 +1431,39 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_NV21TOARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void NV21ToARGBRow_RVV(const uint8_t* src_y,
+                       const uint8_t* src_vu,
+                       uint8_t* dst_argb,
+                       const struct YuvConstants* yuvconstants,
+                       int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r, v_a;
+  vuint8m2x4_t v_dst_argb;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    READNV21(vl, w, src_y, src_vu, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_y += vl;
+    src_vu += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void NV21ToARGBRow_RVV(const uint8_t* src_y,
                        const uint8_t* src_vu,
                        uint8_t* dst_argb,
@@ -773,8 +1491,38 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_NV21TORGB24ROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void NV21ToRGB24Row_RVV(const uint8_t* src_y,
+                        const uint8_t* src_vu,
+                        uint8_t* dst_rgb24,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  uint8_t ub, vr, ug, vg;
+  int16_t yg, bb, bg, br;
+  vuint8m2_t v_u, v_v;
+  vuint8m2_t v_b, v_g, v_r;
+  vuint8m2x3_t v_dst_rgb;
+  vuint16m4_t v_y_16, v_g_16, v_b_16, v_r_16;
+  YUVTORGB_SETUP(yuvconstants, ub, vr, ug, vg, yg, bb, bg, br);
+  do {
+    READNV21(vl, w, src_y, src_vu, v_u, v_v, v_y_16);
+    YUVTORGB(vl, v_u, v_v, ub, vr, ug, vg, yg, bb, bg, br, v_y_16, v_g_16,
+             v_b_16, v_r_16);
+    RGBTORGB8(vl, v_g_16, v_b_16, v_r_16, v_g, v_b, v_r);
+    v_dst_rgb = __riscv_vcreate_v_u8m2x3(v_b, v_g, v_r);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb24, v_dst_rgb, vl);
+    w -= vl;
+    src_y += vl;
+    src_vu += vl;
+    dst_rgb24 += vl * 3;
+  } while (w > 0);
+}
+#else
 void NV21ToRGB24Row_RVV(const uint8_t* src_y,
                         const uint8_t* src_vu,
                         uint8_t* dst_rgb24,
@@ -801,10 +1549,65 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 // Bilinear filter [VLEN/8]x2 -> [VLEN/8]x1
-
 #ifdef HAS_INTERPOLATEROW_RVV
+#ifdef LIBYUV_RVV_HAS_VXRM_ARG
+void InterpolateRow_RVV(uint8_t* dst_ptr,
+                        const uint8_t* src_ptr,
+                        ptrdiff_t src_stride,
+                        int dst_width,
+                        int source_y_fraction) {
+  int y1_fraction = source_y_fraction;
+  int y0_fraction = 256 - y1_fraction;
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
+  size_t dst_w = (size_t)dst_width;
+  assert(source_y_fraction >= 0);
+  assert(source_y_fraction < 256);
+  // Blend 100 / 0 - Copy row unchanged.
+  if (y1_fraction == 0) {
+    do {
+      size_t vl = __riscv_vsetvl_e8m8(dst_w);
+      __riscv_vse8_v_u8m8(dst_ptr, __riscv_vle8_v_u8m8(src_ptr, vl), vl);
+      dst_w -= vl;
+      src_ptr += vl;
+      dst_ptr += vl;
+    } while (dst_w > 0);
+    return;
+  }
+  // Blend 50 / 50.
+  if (y1_fraction == 128) {
+    do {
+      size_t vl = __riscv_vsetvl_e8m8(dst_w);
+      vuint8m8_t row0 = __riscv_vle8_v_u8m8(src_ptr, vl);
+      vuint8m8_t row1 = __riscv_vle8_v_u8m8(src_ptr1, vl);
+      vuint8m8_t row_out =
+          __riscv_vaaddu_vv_u8m8(row0, row1, __RISCV_VXRM_RNU, vl);
+      __riscv_vse8_v_u8m8(dst_ptr, row_out, vl);
+      dst_w -= vl;
+      src_ptr += vl;
+      src_ptr1 += vl;
+      dst_ptr += vl;
+    } while (dst_w > 0);
+    return;
+  }
+  // General purpose row blend.
+  do {
+    size_t vl = __riscv_vsetvl_e8m4(dst_w);
+    vuint8m4_t row0 = __riscv_vle8_v_u8m4(src_ptr, vl);
+    vuint16m8_t acc = __riscv_vwmulu_vx_u16m8(row0, y0_fraction, vl);
+    vuint8m4_t row1 = __riscv_vle8_v_u8m4(src_ptr1, vl);
+    acc = __riscv_vwmaccu_vx_u16m8(acc, y1_fraction, row1, vl);
+    __riscv_vse8_v_u8m4(
+        dst_ptr, __riscv_vnclipu_wx_u8m4(acc, 8, __RISCV_VXRM_RNU, vl), vl);
+    dst_w -= vl;
+    src_ptr += vl;
+    src_ptr1 += vl;
+    dst_ptr += vl;
+  } while (dst_w > 0);
+}
+#else
 void InterpolateRow_RVV(uint8_t* dst_ptr,
                         const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
@@ -862,8 +1665,33 @@
   } while (dst_w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SPLITRGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void SplitRGBRow_RVV(const uint8_t* src_rgb,
+                     uint8_t* dst_r,
+                     uint8_t* dst_g,
+                     uint8_t* dst_b,
+                     int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x3_t v_src = __riscv_vlseg3e8_v_u8m2x3(src_rgb, vl);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_src, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_src, 1);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_src, 2);
+    __riscv_vse8_v_u8m2(dst_r, v_r, vl);
+    __riscv_vse8_v_u8m2(dst_g, v_g, vl);
+    __riscv_vse8_v_u8m2(dst_b, v_b, vl);
+    w -= vl;
+    dst_r += vl;
+    dst_g += vl;
+    dst_b += vl;
+    src_rgb += vl * 3;
+  } while (w > 0);
+}
+#else
 void SplitRGBRow_RVV(const uint8_t* src_rgb,
                      uint8_t* dst_r,
                      uint8_t* dst_g,
@@ -885,8 +1713,31 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_MERGERGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void MergeRGBRow_RVV(const uint8_t* src_r,
+                     const uint8_t* src_g,
+                     const uint8_t* src_b,
+                     uint8_t* dst_rgb,
+                     int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2_t v_r = __riscv_vle8_v_u8m2(src_r, vl);
+    vuint8m2_t v_g = __riscv_vle8_v_u8m2(src_g, vl);
+    vuint8m2_t v_b = __riscv_vle8_v_u8m2(src_b, vl);
+    vuint8m2x3_t v_dst = __riscv_vcreate_v_u8m2x3(v_r, v_g, v_b);
+    __riscv_vsseg3e8_v_u8m2x3(dst_rgb, v_dst, vl);
+    w -= vl;
+    src_r += vl;
+    src_g += vl;
+    src_b += vl;
+    dst_rgb += vl * 3;
+  } while (w > 0);
+}
+#else
 void MergeRGBRow_RVV(const uint8_t* src_r,
                      const uint8_t* src_g,
                      const uint8_t* src_b,
@@ -907,8 +1758,37 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SPLITARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void SplitARGBRow_RVV(const uint8_t* src_argb,
+                      uint8_t* dst_r,
+                      uint8_t* dst_g,
+                      uint8_t* dst_b,
+                      uint8_t* dst_a,
+                      int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src, 2);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src, 3);
+    __riscv_vse8_v_u8m2(dst_a, v_a, vl);
+    __riscv_vse8_v_u8m2(dst_r, v_r, vl);
+    __riscv_vse8_v_u8m2(dst_g, v_g, vl);
+    __riscv_vse8_v_u8m2(dst_b, v_b, vl);
+    w -= vl;
+    dst_a += vl;
+    dst_r += vl;
+    dst_g += vl;
+    dst_b += vl;
+    src_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void SplitARGBRow_RVV(const uint8_t* src_argb,
                       uint8_t* dst_r,
                       uint8_t* dst_g,
@@ -933,8 +1813,34 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_MERGEARGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void MergeARGBRow_RVV(const uint8_t* src_r,
+                      const uint8_t* src_g,
+                      const uint8_t* src_b,
+                      const uint8_t* src_a,
+                      uint8_t* dst_argb,
+                      int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2_t v_r = __riscv_vle8_v_u8m2(src_r, vl);
+    vuint8m2_t v_g = __riscv_vle8_v_u8m2(src_g, vl);
+    vuint8m2_t v_b = __riscv_vle8_v_u8m2(src_b, vl);
+    vuint8m2_t v_a = __riscv_vle8_v_u8m2(src_a, vl);
+    vuint8m2x4_t v_dst = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst, vl);
+    w -= vl;
+    src_r += vl;
+    src_g += vl;
+    src_b += vl;
+    src_a += vl;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void MergeARGBRow_RVV(const uint8_t* src_r,
                       const uint8_t* src_g,
                       const uint8_t* src_b,
@@ -958,8 +1864,33 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SPLITXRGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void SplitXRGBRow_RVV(const uint8_t* src_argb,
+                      uint8_t* dst_r,
+                      uint8_t* dst_g,
+                      uint8_t* dst_b,
+                      int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src, 2);
+    __riscv_vse8_v_u8m2(dst_r, v_r, vl);
+    __riscv_vse8_v_u8m2(dst_g, v_g, vl);
+    __riscv_vse8_v_u8m2(dst_b, v_b, vl);
+    w -= vl;
+    dst_r += vl;
+    dst_g += vl;
+    dst_b += vl;
+    src_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void SplitXRGBRow_RVV(const uint8_t* src_argb,
                       uint8_t* dst_r,
                       uint8_t* dst_g,
@@ -981,8 +1912,33 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_MERGEXRGBROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void MergeXRGBRow_RVV(const uint8_t* src_r,
+                      const uint8_t* src_g,
+                      const uint8_t* src_b,
+                      uint8_t* dst_argb,
+                      int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  vuint8m2_t v_a = __riscv_vmv_v_x_u8m2(255u, vl);
+  do {
+    vuint8m2_t v_r = __riscv_vle8_v_u8m2(src_r, vl);
+    vuint8m2_t v_g = __riscv_vle8_v_u8m2(src_g, vl);
+    vuint8m2_t v_b = __riscv_vle8_v_u8m2(src_b, vl);
+    vuint8m2x4_t v_dst = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst, vl);
+    w -= vl;
+    src_r += vl;
+    src_g += vl;
+    src_b += vl;
+    dst_argb += vl * 4;
+    vl = __riscv_vsetvl_e8m2(w);
+  } while (w > 0);
+}
+#else
 void MergeXRGBRow_RVV(const uint8_t* src_r,
                       const uint8_t* src_g,
                       const uint8_t* src_b,
@@ -1006,8 +1962,29 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SPLITUVROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void SplitUVRow_RVV(const uint8_t* src_uv,
+                    uint8_t* dst_u,
+                    uint8_t* dst_v,
+                    int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m4(w);
+    vuint8m4x2_t v_src = __riscv_vlseg2e8_v_u8m4x2(src_uv, vl);
+    vuint8m4_t v_u = __riscv_vget_v_u8m4x2_u8m4(v_src, 0);
+    vuint8m4_t v_v = __riscv_vget_v_u8m4x2_u8m4(v_src, 1);
+    __riscv_vse8_v_u8m4(dst_u, v_u, vl);
+    __riscv_vse8_v_u8m4(dst_v, v_v, vl);
+    w -= vl;
+    dst_u += vl;
+    dst_v += vl;
+    src_uv += 2 * vl;
+  } while (w > 0);
+}
+#else
 void SplitUVRow_RVV(const uint8_t* src_uv,
                     uint8_t* dst_u,
                     uint8_t* dst_v,
@@ -1026,8 +2003,28 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_MERGEUVROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void MergeUVRow_RVV(const uint8_t* src_u,
+                    const uint8_t* src_v,
+                    uint8_t* dst_uv,
+                    int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m4(w);
+    vuint8m4_t v_u = __riscv_vle8_v_u8m4(src_u, vl);
+    vuint8m4_t v_v = __riscv_vle8_v_u8m4(src_v, vl);
+    vuint8m4x2_t v_dst = __riscv_vcreate_v_u8m4x2(v_u, v_v);
+    __riscv_vsseg2e8_v_u8m4x2(dst_uv, v_dst, vl);
+    w -= vl;
+    src_u += vl;
+    src_v += vl;
+    dst_uv += 2 * vl;
+  } while (w > 0);
+}
+#else
 void MergeUVRow_RVV(const uint8_t* src_u,
                     const uint8_t* src_v,
                     uint8_t* dst_uv,
@@ -1046,6 +2043,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 struct RgbConstants {
   uint8_t kRGBToY[4];
@@ -1080,10 +2078,44 @@
 
 // ARGB expects first 3 values to contain RGB and 4th value is ignored
 #ifdef HAS_ARGBTOYMATRIXROW_RVV
-void ARGBToYMatrixRow_RVV(const uint8_t* src_argb,
-                          uint8_t* dst_y,
-                          int width,
-                          const struct RgbConstants* rgbconstants) {
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+static void ARGBToYMatrixRow_RVV(const uint8_t* src_argb,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
+  assert(width != 0);
+  size_t w = (size_t)width;
+  vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
+  vuint16m4_t v_addy;           // vector is to store kAddY
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  v_by = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[0], vl);
+  v_gy = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[1], vl);
+  v_ry = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[2], vl);
+  v_addy = __riscv_vmv_v_x_u16m4(rgbconstants->kAddY, vl);
+  do {
+    vuint8m2_t v_y;
+    vuint16m4_t v_y_u16;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    v_y_u16 = __riscv_vwmulu_vv_u16m4(v_r, v_ry, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_gy, v_g, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_by, v_b, vl);
+    v_y_u16 = __riscv_vadd_vv_u16m4(v_y_u16, v_addy, vl);
+    v_y = __riscv_vnsrl_wx_u8m2(v_y_u16, 8, vl);
+    __riscv_vse8_v_u8m2(dst_y, v_y, vl);
+    w -= vl;
+    src_argb += 4 * vl;
+    dst_y += vl;
+  } while (w > 0);
+}
+#else
+static void ARGBToYMatrixRow_RVV(const uint8_t* src_argb,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
   assert(width != 0);
   size_t w = (size_t)width;
   vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
@@ -1110,6 +2142,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBTOYROW_RVV
 void ARGBToYRow_RVV(const uint8_t* src_argb, uint8_t* dst_y, int width) {
@@ -1137,10 +2170,44 @@
 
 // RGBA expects first value to be A and ignored, then 3 values to contain RGB.
 #ifdef HAS_RGBATOYMATRIXROW_RVV
-void RGBAToYMatrixRow_RVV(const uint8_t* src_rgba,
-                          uint8_t* dst_y,
-                          int width,
-                          const struct RgbConstants* rgbconstants) {
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+static void RGBAToYMatrixRow_RVV(const uint8_t* src_rgba,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
+  assert(width != 0);
+  size_t w = (size_t)width;
+  vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
+  vuint16m4_t v_addy;           // vector is to store kAddY
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  v_by = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[0], vl);
+  v_gy = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[1], vl);
+  v_ry = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[2], vl);
+  v_addy = __riscv_vmv_v_x_u16m4(rgbconstants->kAddY, vl);
+  do {
+    vuint8m2_t v_y;
+    vuint16m4_t v_y_u16;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_rgba = __riscv_vlseg4e8_v_u8m2x4(src_rgba, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 1);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 2);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_rgba, 3);
+    v_y_u16 = __riscv_vwmulu_vv_u16m4(v_r, v_ry, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_gy, v_g, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_by, v_b, vl);
+    v_y_u16 = __riscv_vadd_vv_u16m4(v_y_u16, v_addy, vl);
+    v_y = __riscv_vnsrl_wx_u8m2(v_y_u16, 8, vl);
+    __riscv_vse8_v_u8m2(dst_y, v_y, vl);
+    w -= vl;
+    src_rgba += 4 * vl;
+    dst_y += vl;
+  } while (w > 0);
+}
+#else
+static void RGBAToYMatrixRow_RVV(const uint8_t* src_rgba,
+                                 uint8_t* dst_y,
+                                 int width,
+                                 const struct RgbConstants* rgbconstants) {
   assert(width != 0);
   size_t w = (size_t)width;
   vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
@@ -1167,6 +2234,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RGBATOYROW_RVV
 void RGBAToYRow_RVV(const uint8_t* src_rgba, uint8_t* dst_y, int width) {
@@ -1187,10 +2255,44 @@
 #endif
 
 #ifdef HAS_RGBTOYMATRIXROW_RVV
-void RGBToYMatrixRow_RVV(const uint8_t* src_rgb,
-                         uint8_t* dst_y,
-                         int width,
-                         const struct RgbConstants* rgbconstants) {
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+static void RGBToYMatrixRow_RVV(const uint8_t* src_rgb,
+                                uint8_t* dst_y,
+                                int width,
+                                const struct RgbConstants* rgbconstants) {
+  assert(width != 0);
+  size_t w = (size_t)width;
+  vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
+  vuint16m4_t v_addy;           // vector is to store kAddY
+  size_t vl = __riscv_vsetvl_e8m2(w);
+  v_by = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[0], vl);
+  v_gy = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[1], vl);
+  v_ry = __riscv_vmv_v_x_u8m2(rgbconstants->kRGBToY[2], vl);
+  v_addy = __riscv_vmv_v_x_u16m4(rgbconstants->kAddY, vl);
+  do {
+    vuint8m2_t v_y;
+    vuint16m4_t v_y_u16;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x3_t v_src_rgb = __riscv_vlseg3e8_v_u8m2x3(src_rgb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x3_u8m2(v_src_rgb, 2);
+    v_y_u16 = __riscv_vwmulu_vv_u16m4(v_r, v_ry, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_gy, v_g, vl);
+    v_y_u16 = __riscv_vwmaccu_vv_u16m4(v_y_u16, v_by, v_b, vl);
+    v_y_u16 = __riscv_vadd_vv_u16m4(v_y_u16, v_addy, vl);
+    v_y = __riscv_vnsrl_wx_u8m2(v_y_u16, 8, vl);
+    __riscv_vse8_v_u8m2(dst_y, v_y, vl);
+    w -= vl;
+    src_rgb += 3 * vl;
+    dst_y += vl;
+  } while (w > 0);
+}
+#else
+static void RGBToYMatrixRow_RVV(const uint8_t* src_rgb,
+                                uint8_t* dst_y,
+                                int width,
+                                const struct RgbConstants* rgbconstants) {
   assert(width != 0);
   size_t w = (size_t)width;
   vuint8m2_t v_by, v_gy, v_ry;  // vectors are to store RGBToY constant
@@ -1217,6 +2319,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_RGB24TOYJROW_RVV
 void RGB24ToYJRow_RVV(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) {
@@ -1246,6 +2349,54 @@
 // dst_argb may be src_argb or src_argb1.
 // src_argb: RGB values have already been pre-multiplied by the a.
 #ifdef HAS_ARGBBLENDROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBBlendRow_RVV(const uint8_t* src_argb,
+                      const uint8_t* src_argb1,
+                      uint8_t* dst_argb,
+                      int width) {
+  size_t w = (size_t)width;
+  size_t vl = __riscv_vsetvlmax_e8m2();
+  // clamp255((((256 - a) * b) >> 8) + f)
+  // = b * (256 - a) / 256 + f
+  // = b - (b * a / 256) + f
+  vuint8m2_t v_255 = __riscv_vmv_v_x_u8m2(255, vl);
+  do {
+    vuint8m2_t v_tmp_b, v_tmp_g, v_tmp_r;
+    vuint8m2_t v_dst_b, v_dst_g, v_dst_r;
+    vuint8m2x4_t v_dst_argb;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src0_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_src0_b = __riscv_vget_v_u8m2x4_u8m2(v_src0_argb, 0);
+    vuint8m2_t v_src0_g = __riscv_vget_v_u8m2x4_u8m2(v_src0_argb, 1);
+    vuint8m2_t v_src0_r = __riscv_vget_v_u8m2x4_u8m2(v_src0_argb, 2);
+    vuint8m2_t v_src0_a = __riscv_vget_v_u8m2x4_u8m2(v_src0_argb, 3);
+    vuint8m2x4_t v_src1_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb1, vl);
+    vuint8m2_t v_src1_b = __riscv_vget_v_u8m2x4_u8m2(v_src1_argb, 0);
+    vuint8m2_t v_src1_g = __riscv_vget_v_u8m2x4_u8m2(v_src1_argb, 1);
+    vuint8m2_t v_src1_r = __riscv_vget_v_u8m2x4_u8m2(v_src1_argb, 2);
+
+    v_tmp_b = __riscv_vmulhu_vv_u8m2(v_src1_b, v_src0_a, vl);
+    v_tmp_g = __riscv_vmulhu_vv_u8m2(v_src1_g, v_src0_a, vl);
+    v_tmp_r = __riscv_vmulhu_vv_u8m2(v_src1_r, v_src0_a, vl);
+
+    v_dst_b = __riscv_vsub_vv_u8m2(v_src1_b, v_tmp_b, vl);
+    v_dst_g = __riscv_vsub_vv_u8m2(v_src1_g, v_tmp_g, vl);
+    v_dst_r = __riscv_vsub_vv_u8m2(v_src1_r, v_tmp_r, vl);
+
+    v_dst_b = __riscv_vsaddu_vv_u8m2(v_dst_b, v_src0_b, vl);
+    v_dst_g = __riscv_vsaddu_vv_u8m2(v_dst_g, v_src0_g, vl);
+    v_dst_r = __riscv_vsaddu_vv_u8m2(v_dst_r, v_src0_r, vl);
+
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_dst_b, v_dst_g, v_dst_r, v_255);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+
+    w -= vl;
+    src_argb += 4 * vl;
+    src_argb1 += 4 * vl;
+    dst_argb += 4 * vl;
+  } while (w > 0);
+}
+#else
 void ARGBBlendRow_RVV(const uint8_t* src_argb,
                       const uint8_t* src_argb1,
                       uint8_t* dst_argb,
@@ -1287,6 +2438,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_BLENDPLANEROW_RVV
 void BlendPlaneRow_RVV(const uint8_t* src0,
@@ -1323,6 +2475,41 @@
 
 // Attenuate: (f * a + 255) >> 8
 #ifdef HAS_ARGBATTENUATEROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBAttenuateRow_RVV(const uint8_t* src_argb,
+                          uint8_t* dst_argb,
+                          int width) {
+  size_t w = (size_t)width;
+  do {
+    vuint16m4_t v_ba_16, v_ga_16, v_ra_16;
+    vuint8m2x4_t v_dst_argb;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_b = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 0);
+    vuint8m2_t v_g = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 1);
+    vuint8m2_t v_r = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 2);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 3);
+    // f * a
+    v_ba_16 = __riscv_vwmulu_vv_u16m4(v_b, v_a, vl);
+    v_ga_16 = __riscv_vwmulu_vv_u16m4(v_g, v_a, vl);
+    v_ra_16 = __riscv_vwmulu_vv_u16m4(v_r, v_a, vl);
+    // f * a + 255
+    v_ba_16 = __riscv_vadd_vx_u16m4(v_ba_16, 255u, vl);
+    v_ga_16 = __riscv_vadd_vx_u16m4(v_ga_16, 255u, vl);
+    v_ra_16 = __riscv_vadd_vx_u16m4(v_ra_16, 255u, vl);
+    // (f * a + 255) >> 8
+    v_b = __riscv_vnsrl_wx_u8m2(v_ba_16, 8, vl);
+    v_g = __riscv_vnsrl_wx_u8m2(v_ga_16, 8, vl);
+    v_r = __riscv_vnsrl_wx_u8m2(v_ra_16, 8, vl);
+
+    v_dst_argb = __riscv_vcreate_v_u8m2x4(v_b, v_g, v_r, v_a);
+    __riscv_vsseg4e8_v_u8m2x4(dst_argb, v_dst_argb, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void ARGBAttenuateRow_RVV(const uint8_t* src_argb,
                           uint8_t* dst_argb,
                           int width) {
@@ -1351,8 +2538,25 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBEXTRACTALPHAROW_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ARGBExtractAlphaRow_RVV(const uint8_t* src_argb,
+                             uint8_t* dst_a,
+                             int width) {
+  size_t w = (size_t)width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src_argb = __riscv_vlseg4e8_v_u8m2x4(src_argb, vl);
+    vuint8m2_t v_a = __riscv_vget_v_u8m2x4_u8m2(v_src_argb, 3);
+    __riscv_vse8_v_u8m2(dst_a, v_a, vl);
+    w -= vl;
+    src_argb += vl * 4;
+    dst_a += vl;
+  } while (w > 0);
+}
+#else
 void ARGBExtractAlphaRow_RVV(const uint8_t* src_argb,
                              uint8_t* dst_a,
                              int width) {
@@ -1368,6 +2572,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_ARGBCOPYYTOALPHAROW_RVV
 void ARGBCopyYToAlphaRow_RVV(const uint8_t* src, uint8_t* dst, int width) {
diff --git a/source/row_sme.cc b/source/row_sme.cc
new file mode 100644
index 0000000..1cbc42f
--- /dev/null
+++ b/source/row_sme.cc
@@ -0,0 +1,1092 @@
+/*
+ *  Copyright 2024 The LibYuv 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 "libyuv/row.h"
+#include "libyuv/row_sve.h"
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+
+// Read twice as much data from YUV, putting the even elements from the Y data
+// in z0.h and odd elements in z1.h.
+#define READYUV444_SVE_2X                        \
+  "ld1b       {z0.b}, p1/z, [%[src_y]]       \n" \
+  "ld1b       {z2.b}, p1/z, [%[src_u]]       \n" \
+  "ld1b       {z3.b}, p1/z, [%[src_v]]       \n" \
+  "incb       %[src_y]                       \n" \
+  "incb       %[src_u]                       \n" \
+  "incb       %[src_v]                       \n" \
+  "prfm       pldl1keep, [%[src_y], 448]     \n" \
+  "prfm       pldl1keep, [%[src_u], 128]     \n" \
+  "prfm       pldl1keep, [%[src_v], 128]     \n" \
+  "trn2       z1.b, z0.b, z0.b               \n" \
+  "trn1       z0.b, z0.b, z0.b               \n"
+
+#define I444TORGB_SVE_2X                                  \
+  "umulh      z0.h, z24.h, z0.h              \n" /* Y0 */ \
+  "umulh      z1.h, z24.h, z1.h              \n" /* Y1 */ \
+  "umullb     z6.h, z30.b, z2.b              \n"          \
+  "umullt     z7.h, z30.b, z2.b              \n"          \
+  "umullb     z4.h, z28.b, z2.b              \n" /* DB */ \
+  "umullt     z2.h, z28.b, z2.b              \n" /* DB */ \
+  "umlalb     z6.h, z31.b, z3.b              \n" /* DG */ \
+  "umlalt     z7.h, z31.b, z3.b              \n" /* DG */ \
+  "umullb     z5.h, z29.b, z3.b              \n" /* DR */ \
+  "umullt     z3.h, z29.b, z3.b              \n" /* DR */ \
+  "add        z17.h, z0.h, z26.h             \n" /* G */  \
+  "add        z21.h, z1.h, z26.h             \n" /* G */  \
+  "add        z16.h, z0.h, z4.h              \n" /* B */  \
+  "add        z20.h, z1.h, z2.h              \n" /* B */  \
+  "add        z18.h, z0.h, z5.h              \n" /* R */  \
+  "add        z22.h, z1.h, z3.h              \n" /* R */  \
+  "uqsub      z17.h, z17.h, z6.h             \n" /* G */  \
+  "uqsub      z21.h, z21.h, z7.h             \n" /* G */  \
+  "uqsub      z16.h, z16.h, z25.h            \n" /* B */  \
+  "uqsub      z20.h, z20.h, z25.h            \n" /* B */  \
+  "uqsub      z18.h, z18.h, z27.h            \n" /* R */  \
+  "uqsub      z22.h, z22.h, z27.h            \n" /* R */
+
+#define RGBTOARGB8_SVE_2X                                 \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.b */ \
+  "uqshrnb     z16.b, z16.h, #6     \n" /* B0 */          \
+  "uqshrnb     z17.b, z17.h, #6     \n" /* G0 */          \
+  "uqshrnb     z18.b, z18.h, #6     \n" /* R0 */          \
+  "uqshrnt     z16.b, z20.h, #6     \n" /* B1 */          \
+  "uqshrnt     z17.b, z21.h, #6     \n" /* G1 */          \
+  "uqshrnt     z18.b, z22.h, #6     \n" /* R1 */
+
+__arm_locally_streaming void I444ToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  uint64_t vl;
+  asm volatile(
+      "cntb     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // A
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.b                                    \n"
+      "1:                                               \n"  //
+      READYUV444_SVE_2X I444TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+      "incb     %[dst_argb], all, mul #4                \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.b, wzr, %w[width]                    \n"  //
+      READYUV444_SVE_2X I444TORGB_SVE_2X RGBTOARGB8_SVE_2X
+      "st4b     {z16.b, z17.b, z18.b, z19.b}, p1, [%[dst_argb]] \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+__arm_locally_streaming void I400ToARGBRow_SME(
+    const uint8_t* src_y,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  I400ToARGBRow_SVE_SC(src_y, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I422ToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  I422ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I422ToRGB24Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422ToRGB24Row_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I422ToRGB565Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_rgb565,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422ToRGB565Row_SVE_SC(src_y, src_u, src_v, dst_rgb565, yuvconstants, width);
+}
+
+__arm_locally_streaming void I422ToARGB1555Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb1555,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422ToARGB1555Row_SVE_SC(src_y, src_u, src_v, dst_argb1555, yuvconstants,
+                           width);
+}
+
+__arm_locally_streaming void I422ToARGB4444Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb4444,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422ToARGB4444Row_SVE_SC(src_y, src_u, src_v, dst_argb4444, yuvconstants,
+                           width);
+}
+
+__arm_locally_streaming void I422ToRGBARow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422ToRGBARow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I422AlphaToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    const uint8_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I422AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+__arm_locally_streaming void I444AlphaToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_u,
+    const uint8_t* src_v,
+    const uint8_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I444AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+__arm_locally_streaming void NV12ToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_uv,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  NV12ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void NV21ToARGBRow_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_vu,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  NV21ToARGBRow_SVE_SC(src_y, src_vu, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void NV12ToRGB24Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_uv,
+    uint8_t* dst_rgb24,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  NV12ToRGB24Row_SVE_SC(src_y, src_uv, dst_rgb24, yuvconstants, width);
+}
+
+__arm_locally_streaming void NV21ToRGB24Row_SME(
+    const uint8_t* src_y,
+    const uint8_t* src_vu,
+    uint8_t* dst_rgb24,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  NV21ToRGB24Row_SVE_SC(src_y, src_vu, dst_rgb24, yuvconstants, width);
+}
+
+__arm_locally_streaming void YUY2ToARGBRow_SME(
+    const uint8_t* src_yuy2,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  YUY2ToARGBRow_SVE_SC(src_yuy2, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void UYVYToARGBRow_SME(
+    const uint8_t* src_uyvy,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  UYVYToARGBRow_SVE_SC(src_uyvy, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I210ToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I210ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I210AlphaToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    const uint16_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I210AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+__arm_locally_streaming void I210ToAR30Row_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_ar30,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I210ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+__arm_locally_streaming void P210ToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_uv,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  P210ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void P210ToAR30Row_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_uv,
+    uint8_t* dst_ar30,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  P210ToAR30Row_SVE_SC(src_y, src_uv, dst_ar30, yuvconstants, width);
+}
+
+__arm_locally_streaming void I410ToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I410ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void I410AlphaToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    const uint16_t* src_a,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I410AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+__arm_locally_streaming void I410ToAR30Row_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_ar30,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I410ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+__arm_locally_streaming void P410ToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_uv,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  P410ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void P410ToAR30Row_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_uv,
+    uint8_t* dst_ar30,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  P410ToAR30Row_SVE_SC(src_y, src_uv, dst_ar30, yuvconstants, width);
+}
+
+__arm_locally_streaming void I212ToAR30Row_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_ar30,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I212ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+__arm_locally_streaming void I212ToARGBRow_SME(
+    const uint16_t* src_y,
+    const uint16_t* src_u,
+    const uint16_t* src_v,
+    uint8_t* dst_argb,
+    const struct YuvConstants* yuvconstants,
+    int width) {
+  I212ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+__arm_locally_streaming void MultiplyRow_16_SME(const uint16_t* src_y,
+                                                uint16_t* dst_y,
+                                                int scale,
+                                                int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  int vl;
+  asm volatile(
+      "cnth    %x[vl]                                   \n"
+      "mov     z0.h, %w[scale]                          \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "b.lt    2f                                       \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue   p0.h                                     \n"
+      "1:                                               \n"
+      "ld1h    {z1.h}, p0/z, [%[src_y]]                 \n"
+      "incb    %[src_y]                                 \n"
+      "mul     z1.h, z0.h, z1.h                         \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st1h    {z1.h}, p0, [%[dst_y]]                   \n"
+      "incb    %[dst_y]                                 \n"
+      "b.ge    1b                                       \n"
+
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.h, wzr, %w[width]                     \n"
+      "ld1h    {z1.h}, p0/z, [%[src_y]]                 \n"
+      "mul     z1.h, z0.h, z1.h                         \n"
+      "st1h    {z1.h}, p0, [%[dst_y]]                   \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),  // %[src_y]
+        [dst_y] "+r"(dst_y),  // %[dst_y]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      : [scale] "r"(scale)    // %[scale]
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ARGBMultiplyRow_SME(const uint8_t* src_argb,
+                                                 const uint8_t* src_argb1,
+                                                 uint8_t* dst_argb,
+                                                 int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  width *= 4;
+  int vl;
+  asm volatile(
+      "cntb    %x[vl]                                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "b.lt    2f                                       \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue   p0.b                                     \n"
+      "1:                                               \n"
+      "ld1b    {z0.b}, p0/z, [%[src_argb]]              \n"
+      "ld1b    {z1.b}, p0/z, [%[src_argb1]]             \n"
+      "incb    %[src_argb]                              \n"
+      "incb    %[src_argb1]                             \n"
+      "umullb  z2.h, z0.b, z1.b                         \n"
+      "umullt  z1.h, z0.b, z1.b                         \n"
+      "rshrnb  z0.b, z2.h, #8                           \n"
+      "rshrnt  z0.b, z1.h, #8                           \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st1b    {z0.b}, p0, [%[dst_argb]]                \n"
+      "incb    %[dst_argb]                              \n"
+      "b.ge    1b                                       \n"
+
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.b, wzr, %w[width]                     \n"
+      "ld1b    {z0.b}, p0/z, [%[src_argb]]              \n"
+      "ld1b    {z1.b}, p0/z, [%[src_argb1]]             \n"
+      "umullb  z2.h, z0.b, z1.b                         \n"
+      "umullt  z1.h, z0.b, z1.b                         \n"
+      "rshrnb  z0.b, z2.h, #8                           \n"
+      "rshrnt  z0.b, z1.h, #8                           \n"
+      "st1b    {z0.b}, p0, [%[dst_argb]]                \n"
+
+      "99:                                              \n"
+      : [src_argb] "+r"(src_argb),    // %[src_argb]
+        [src_argb1] "+r"(src_argb1),  // %[src_argb1]
+        [dst_argb] "+r"(dst_argb),    // %[dst_argb]
+        [width] "+r"(width),          // %[width]
+        [vl] "=&r"(vl)                // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "z2", "p0", "p1");
+}
+
+__arm_locally_streaming void MergeUVRow_SME(const uint8_t* src_u,
+                                            const uint8_t* src_v,
+                                            uint8_t* dst_uv,
+                                            int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  int vl;
+  asm volatile(
+      "cntb    %x[vl]                                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "b.lt    2f                                       \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue   p0.b                                     \n"
+      "1:                                               \n"
+      "ld1b    {z1.b}, p0/z, [%[src_u]]                 \n"
+      "ld1b    {z2.b}, p0/z, [%[src_v]]                 \n"
+      "incb    %[src_u]                                 \n"
+      "incb    %[src_v]                                 \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st2b    {z1.b, z2.b}, p0, [%[dst_uv]]            \n"
+      "incb    %[dst_uv], all, mul #2                   \n"
+      "b.ge    1b                                       \n"
+
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.b, wzr, %w[width]                     \n"
+      "ld1b    {z1.b}, p0/z, [%[src_u]]                 \n"
+      "ld1b    {z2.b}, p0/z, [%[src_v]]                 \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st2b    {z1.b, z2.b}, p0, [%[dst_uv]]            \n"
+
+      "99:                                              \n"
+      : [src_u] "+r"(src_u),    // %[src_u]
+        [src_v] "+r"(src_v),    // %[src_v]
+        [dst_uv] "+r"(dst_uv),  // %[dst_uv]
+        [width] "+r"(width),    // %[width]
+        [vl] "=&r"(vl)          // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "z2", "p0");
+}
+
+__arm_locally_streaming void MergeUVRow_16_SME(const uint16_t* src_u,
+                                               const uint16_t* src_v,
+                                               uint16_t* dst_uv,
+                                               int depth,
+                                               int width) {
+  int shift = 16 - depth;
+  // Streaming-SVE only, no use of ZA tile.
+  int vl;
+  asm volatile(
+      "cnth    %x[vl]                                   \n"
+      "mov     z0.h, %w[shift]                          \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "b.lt    2f                                       \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue   p0.h                                     \n"
+      "1:                                               \n"
+      "ld1h    {z1.h}, p0/z, [%[src_u]]                 \n"
+      "ld1h    {z2.h}, p0/z, [%[src_v]]                 \n"
+      "incb    %[src_u]                                 \n"
+      "incb    %[src_v]                                 \n"
+      "lsl     z1.h, p0/m, z1.h, z0.h                   \n"
+      "lsl     z2.h, p0/m, z2.h, z0.h                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st2h    {z1.h, z2.h}, p0, [%[dst_uv]]            \n"
+      "incb    %[dst_uv], all, mul #2                   \n"
+      "b.ge    1b                                       \n"
+
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.h, wzr, %w[width]                     \n"
+      "ld1h    {z1.h}, p0/z, [%[src_u]]                 \n"
+      "ld1h    {z2.h}, p0/z, [%[src_v]]                 \n"
+      "lsl     z1.h, p0/m, z1.h, z0.h                   \n"
+      "lsl     z2.h, p0/m, z2.h, z0.h                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st2h    {z1.h, z2.h}, p0, [%[dst_uv]]            \n"
+
+      "99:                                              \n"
+      : [src_u] "+r"(src_u),    // %[src_u]
+        [src_v] "+r"(src_v),    // %[src_v]
+        [dst_uv] "+r"(dst_uv),  // %[dst_uv]
+        [width] "+r"(width),    // %[width]
+        [vl] "=&r"(vl)          // %[vl]
+      : [shift] "r"(shift)      // %[shift]
+      : "memory", "cc", "z0", "z1", "z2", "p0");
+}
+
+// Use scale to convert lsb formats to msb, depending how many bits there are:
+// 32768 = 9 bits = shr 1
+// 16384 = 10 bits = shr 2
+// 4096 = 12 bits = shr 4
+// 256 = 16 bits = shr 8
+__arm_locally_streaming void Convert16To8Row_SME(const uint16_t* src_y,
+                                                 uint8_t* dst_y,
+                                                 int scale,
+                                                 int width) {
+  // 15 - clz(scale), + 8 to shift result into the high half of the lane to
+  // saturate, then we can just use UZP2 to narrow rather than a pair of
+  // saturating narrow instructions.
+  int shift = 23 - __builtin_clz((int32_t)scale);
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                  \n"
+      "dup      z0.h, %w[shift]                         \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.b                                    \n"
+      "1:                                               \n"
+      "ld1h     {z1.h}, p0/z, [%[src_y]]                \n"
+      "ld1h     {z2.h}, p0/z, [%[src_y], #1, mul vl]    \n"
+      "incb     %[src_y], all, mul #2                   \n"
+      "uqshl    z1.h, p0/m, z1.h, z0.h                  \n"
+      "uqshl    z2.h, p0/m, z2.h, z0.h                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "uzp2     z1.b, z1.b, z2.b                        \n"
+      "st1b     {z1.b}, p0, [%[dst_y]]                  \n"
+      "incb     %[dst_y]                                \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      // We need separate predicates for the load and store instructions since
+      // they are operating on different element sizes (.b vs .h).
+      "cnth     %x[vl]                                  \n"
+      "whilelt  p0.h, wzr, %w[width]                    \n"
+      "whilelt  p1.h, %w[vl], %w[width]                 \n"
+      "whilelt  p2.b, wzr, %w[width]                    \n"
+      "ld1h     {z1.h}, p0/z, [%[src_y]]                \n"
+      "ld1h     {z2.h}, p1/z, [%[src_y], #1, mul vl]    \n"
+      "uqshl    z1.h, p0/m, z1.h, z0.h                  \n"
+      "uqshl    z2.h, p1/m, z2.h, z0.h                  \n"
+      "uzp2     z1.b, z1.b, z2.b                        \n"
+      "st1b     {z1.b}, p2, [%[dst_y]]                  \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),  // %[src_y]
+        [dst_y] "+r"(dst_y),  // %[dst_y]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      : [shift] "r"(shift)    // %[shift]
+      : "cc", "memory", "z0", "z1", "z2", "p0", "p1", "p2");
+}
+
+__arm_locally_streaming void CopyRow_SME(const uint8_t* src,
+                                         uint8_t* dst,
+                                         int width) {
+  // Streaming-SVE only, no use of ZA tile.
+  int vl;
+  asm volatile(
+      "cntb    %x[vl]                                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "b.lt    2f                                       \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue   p0.b                                     \n"
+      "1:                                               \n"
+      "ld1b    {z0.b}, p0/z, [%[src]]                   \n"
+      "incb    %[src]                                   \n"
+      "subs    %w[width], %w[width], %w[vl]             \n"
+      "st1b    {z0.b}, p0, [%[dst]]                     \n"
+      "incb    %[dst]                                   \n"
+      "b.ge    1b                                       \n"
+
+      "2:                                               \n"
+      "adds    %w[width], %w[width], %w[vl]             \n"
+      "b.eq    99f                                      \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.b, wzr, %w[width]                     \n"
+      "ld1b    {z0.b}, p0/z, [%[src]]                   \n"
+      "st1b    {z0.b}, p0, [%[dst]]                     \n"
+
+      "99:                                              \n"
+      : [src] "+r"(src),      // %[src]
+        [dst] "+r"(dst),      // %[dst]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      :
+      : "memory", "cc", "z0", "p0");
+}
+
+__arm_locally_streaming static void HalfRow_SME(uint8_t* dst_ptr,
+                                                const uint8_t* src_ptr,
+                                                ptrdiff_t src_stride,
+                                                int width) {
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
+
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.b                                    \n"
+      "1:                                               \n"
+      "ld1b     {z2.b}, p0/z, [%[src_ptr]]              \n"
+      "ld1b     {z3.b}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "urhadd   z2.b, p0/m, z2.b, z3.b                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st1b     {z2.b}, p0, [%[dst_ptr]]                \n"
+      "incb     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.b, wzr, %w[width]                    \n"
+      "ld1b     {z2.b}, p0/z, [%[src_ptr]]              \n"
+      "ld1b     {z3.b}, p0/z, [%[src_ptr1]]             \n"
+      "urhadd   z2.b, p0/m, z2.b, z3.b                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st1b     {z2.b}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),    // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),  // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),    // %[dst_ptr]
+        [width] "+r"(width),        // %[width]
+        [vl] "=&r"(vl)              // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "z2", "z3", "p0");
+}
+
+__arm_locally_streaming void InterpolateRow_SME(uint8_t* dst_ptr,
+                                                const uint8_t* src_ptr,
+                                                ptrdiff_t src_stride,
+                                                int width,
+                                                int source_y_fraction) {
+  int y1_fraction = source_y_fraction;
+  int y0_fraction = 256 - y1_fraction;
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
+
+  if (y0_fraction == 0) {
+    CopyRow_SME(src_ptr1, dst_ptr, width);
+    return;
+  }
+  if (y0_fraction == 128) {
+    HalfRow_SME(dst_ptr, src_ptr, src_stride, width);
+    return;
+  }
+  if (y0_fraction == 256) {
+    CopyRow_SME(src_ptr, dst_ptr, width);
+    return;
+  }
+
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                  \n"
+      "dup      z0.b, %w[y0_fraction]                   \n"
+      "dup      z1.b, %w[y1_fraction]                   \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.b                                    \n"
+      "1:                                               \n"
+      "ld1b     {z2.b}, p0/z, [%[src_ptr]]              \n"
+      "ld1b     {z3.b}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "umullb   z4.h, z2.b, z0.b                        \n"
+      "umullt   z2.h, z2.b, z0.b                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "umlalb   z4.h, z3.b, z1.b                        \n"
+      "umlalt   z2.h, z3.b, z1.b                        \n"
+      "rshrnb   z3.b, z4.h, #8                          \n"
+      "rshrnt   z3.b, z2.h, #8                          \n"
+      "st1b     {z3.b}, p0, [%[dst_ptr]]                \n"
+      "incb     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.b, wzr, %w[width]                    \n"
+      "ld1b     {z2.b}, p0/z, [%[src_ptr]]              \n"
+      "ld1b     {z3.b}, p0/z, [%[src_ptr1]]             \n"
+      "umullb   z4.h, z2.b, z0.b                        \n"
+      "umullt   z2.h, z2.b, z0.b                        \n"
+      "umlalb   z4.h, z3.b, z1.b                        \n"
+      "umlalt   z2.h, z3.b, z1.b                        \n"
+      "rshrnb   z3.b, z4.h, #8                          \n"
+      "rshrnt   z3.b, z2.h, #8                          \n"
+      "st1b     {z3.b}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),         // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),       // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),         // %[dst_ptr]
+        [width] "+r"(width),             // %[width]
+        [vl] "=&r"(vl)                   // %[vl]
+      : [y0_fraction] "r"(y0_fraction),  // %[y0_fraction]
+        [y1_fraction] "r"(y1_fraction)   // %[y1_fraction]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "p0");
+}
+
+__arm_locally_streaming static void HalfRow_16_SME(uint16_t* dst_ptr,
+                                                   const uint16_t* src_ptr,
+                                                   ptrdiff_t src_stride,
+                                                   int width) {
+  const uint16_t* src_ptr1 = src_ptr + src_stride;
+
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.h                                    \n"
+      "1:                                               \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "urhadd   z2.h, p0/m, z2.h, z3.h                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st1h     {z2.h}, p0, [%[dst_ptr]]                \n"
+      "incb     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.h, wzr, %w[width]                    \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "urhadd   z2.h, p0/m, z2.h, z3.h                  \n"
+      "st1h     {z2.h}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),    // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),  // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),    // %[dst_ptr]
+        [width] "+r"(width),        // %[width]
+        [vl] "=&r"(vl)              // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "z2", "z3", "p0");
+}
+
+__arm_locally_streaming void InterpolateRow_16_SME(uint16_t* dst_ptr,
+                                                   const uint16_t* src_ptr,
+                                                   ptrdiff_t src_stride,
+                                                   int width,
+                                                   int source_y_fraction) {
+  int y1_fraction = source_y_fraction;
+  int y0_fraction = 256 - y1_fraction;
+  const uint16_t* src_ptr1 = src_ptr + src_stride;
+
+  if (y0_fraction == 0) {
+    CopyRow_SME((const uint8_t*)src_ptr1, (uint8_t*)dst_ptr,
+                width * sizeof(uint16_t));
+    return;
+  }
+  if (y0_fraction == 128) {
+    HalfRow_16_SME(dst_ptr, src_ptr, src_stride, width);
+    return;
+  }
+  if (y0_fraction == 256) {
+    CopyRow_SME((const uint8_t*)src_ptr, (uint8_t*)dst_ptr,
+                width * sizeof(uint16_t));
+    return;
+  }
+
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "dup      z0.h, %w[y0_fraction]                   \n"
+      "dup      z1.h, %w[y1_fraction]                   \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.h                                    \n"
+      "1:                                               \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "umullb   z4.s, z2.h, z0.h                        \n"
+      "umullt   z2.s, z2.h, z0.h                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "umlalb   z4.s, z3.h, z1.h                        \n"
+      "umlalt   z2.s, z3.h, z1.h                        \n"
+      "rshrnb   z3.h, z4.s, #8                          \n"
+      "rshrnt   z3.h, z2.s, #8                          \n"
+      "st1h     {z3.h}, p0, [%[dst_ptr]]                \n"
+      "incb     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.h, wzr, %w[width]                    \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "umullb   z4.s, z2.h, z0.h                        \n"
+      "umullt   z2.s, z2.h, z0.h                        \n"
+      "umlalb   z4.s, z3.h, z1.h                        \n"
+      "umlalt   z2.s, z3.h, z1.h                        \n"
+      "rshrnb   z3.h, z4.s, #8                          \n"
+      "rshrnt   z3.h, z2.s, #8                          \n"
+      "st1h     {z3.h}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),         // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),       // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),         // %[dst_ptr]
+        [width] "+r"(width),             // %[width]
+        [vl] "=&r"(vl)                   // %[vl]
+      : [y0_fraction] "r"(y0_fraction),  // %[y0_fraction]
+        [y1_fraction] "r"(y1_fraction)   // %[y1_fraction]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "p0");
+}
+
+__arm_locally_streaming static void HalfRow_16To8_SME(uint8_t* dst_ptr,
+                                                      const uint16_t* src_ptr,
+                                                      ptrdiff_t src_stride,
+                                                      int scale,
+                                                      int width) {
+  const uint16_t* src_ptr1 = src_ptr + src_stride;
+
+  // 15 - clz(scale), + 8 to shift result into the high half of the lane to
+  // saturate, then we can just use UZP2 to narrow rather than a pair of
+  // saturating narrow instructions.
+  int shift = 23 - __builtin_clz((int32_t)scale);
+
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                  \n"
+      "dup      z31.h, %w[shift]                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.h                                    \n"
+      "1:                                               \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "urhadd   z2.h, p0/m, z2.h, z3.h                  \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "uqshl    z2.h, p0/m, z2.h, z31.h                 \n"
+      "shrnb    z2.b, z2.h, #8                          \n"
+      "st1b     {z2.h}, p0, [%[dst_ptr]]                \n"
+      "inch     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.h, wzr, %w[width]                    \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "urhadd   z2.h, p0/m, z2.h, z3.h                  \n"
+      "uqshl    z2.h, p0/m, z2.h, z31.h                 \n"
+      "shrnb    z2.b, z2.h, #8                          \n"
+      "st1b     {z2.h}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),    // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),  // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),    // %[dst_ptr]
+        [width] "+r"(width),        // %[width]
+        [vl] "=&r"(vl)              // %[vl]
+      : [shift] "r"(shift)          // %[shift]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z31", "p0");
+}
+
+// Use scale to convert lsb formats to msb, depending how many bits there are:
+// 32768 = 9 bits
+// 16384 = 10 bits
+// 4096 = 12 bits
+// 256 = 16 bits
+// TODO(fbarchard): change scale to bits
+__arm_locally_streaming void InterpolateRow_16To8_SME(uint8_t* dst_ptr,
+                                                      const uint16_t* src_ptr,
+                                                      ptrdiff_t src_stride,
+                                                      int scale,
+                                                      int width,
+                                                      int source_y_fraction) {
+  int y1_fraction = source_y_fraction;
+  int y0_fraction = 256 - y1_fraction;
+  const uint16_t* src_ptr1 = src_ptr + src_stride;
+
+  // y0_fraction == 0 is never called here.
+  if (y0_fraction == 128) {
+    HalfRow_16To8_SME(dst_ptr, src_ptr, src_stride, scale, width);
+    return;
+  }
+  if (y0_fraction == 256) {
+    Convert16To8Row_SME(src_ptr, dst_ptr, scale, width);
+    return;
+  }
+
+  // 15 - clz(scale), + 8 to shift result into the high half of the lane to
+  // saturate, then we can just use UZP2 to narrow rather than a pair of
+  // saturating narrow instructions.
+  int shift = 23 - __builtin_clz((int32_t)scale);
+
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                  \n"
+      "dup      z31.h, %w[shift]                        \n"
+      "dup      z0.h, %w[y0_fraction]                   \n"
+      "dup      z1.h, %w[y1_fraction]                   \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p0.h                                    \n"
+      "1:                                               \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "incb     %[src_ptr]                              \n"
+      "incb     %[src_ptr1]                             \n"
+      "umullb   z4.s, z2.h, z0.h                        \n"
+      "umullt   z2.s, z2.h, z0.h                        \n"
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "umlalb   z4.s, z3.h, z1.h                        \n"
+      "umlalt   z2.s, z3.h, z1.h                        \n"
+      "rshrnb   z3.h, z4.s, #8                          \n"
+      "rshrnt   z3.h, z2.s, #8                          \n"
+      "uqshl    z3.h, p0/m, z3.h, z31.h                 \n"
+      "shrnb    z3.b, z3.h, #8                          \n"
+      "st1b     {z3.h}, p0, [%[dst_ptr]]                \n"
+      "inch     %[dst_ptr]                              \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p0.h, wzr, %w[width]                    \n"
+      "ld1h     {z2.h}, p0/z, [%[src_ptr]]              \n"
+      "ld1h     {z3.h}, p0/z, [%[src_ptr1]]             \n"
+      "umullb   z4.s, z2.h, z0.h                        \n"
+      "umullt   z2.s, z2.h, z0.h                        \n"
+      "umlalb   z4.s, z3.h, z1.h                        \n"
+      "umlalt   z2.s, z3.h, z1.h                        \n"
+      "rshrnb   z3.h, z4.s, #8                          \n"
+      "rshrnt   z3.h, z2.s, #8                          \n"
+      "uqshl    z3.h, p0/m, z3.h, z31.h                 \n"
+      "shrnb    z3.b, z3.h, #8                          \n"
+      "st1b     {z3.h}, p0, [%[dst_ptr]]                \n"
+
+      "99:                                              \n"
+      : [src_ptr] "+r"(src_ptr),         // %[src_ptr]
+        [src_ptr1] "+r"(src_ptr1),       // %[src_ptr1]
+        [dst_ptr] "+r"(dst_ptr),         // %[dst_ptr]
+        [width] "+r"(width),             // %[width]
+        [vl] "=&r"(vl)                   // %[vl]
+      : [y0_fraction] "r"(y0_fraction),  // %[y0_fraction]
+        [y1_fraction] "r"(y1_fraction),  // %[y1_fraction]
+        [shift] "r"(shift)               // %[shift]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "z31", "p0");
+}
+
+__arm_locally_streaming void Convert8To8Row_SME(const uint8_t* src_y,
+                                                uint8_t* dst_y,
+                                                int scale,
+                                                int bias,
+                                                int width) {
+  Convert8To8Row_SVE_SC(src_y, dst_y, scale, bias, width);
+}
+
+#endif  // !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) &&
+        // defined(__aarch64__)
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
diff --git a/source/row_sve.cc b/source/row_sve.cc
new file mode 100644
index 0000000..ba89b16
--- /dev/null
+++ b/source/row_sve.cc
@@ -0,0 +1,1276 @@
+/*
+ *  Copyright 2024 The LibYuv 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 "libyuv/row_sve.h"
+#include "libyuv/row.h"
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__)
+
+#define RGBTOARGB8_SVE_2X                                 \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h,  A: z19.b */ \
+  "uqshrnb     z16.b, z16.h, #6     \n" /* B0 */          \
+  "uqshrnb     z17.b, z17.h, #6     \n" /* G0 */          \
+  "uqshrnb     z18.b, z18.h, #6     \n" /* R0 */          \
+  "uqshrnt     z16.b, z20.h, #6     \n" /* B1 */          \
+  "uqshrnt     z17.b, z21.h, #6     \n" /* G1 */          \
+  "uqshrnt     z18.b, z22.h, #6     \n" /* R1 */
+
+#define RGBTOARGB8_SVE_TOP_2X                        \
+  /* Inputs: B: z16.h,  G: z17.h,  R: z18.h */       \
+  "uqshl     z16.h, p0/m, z16.h, #2     \n" /* B0 */ \
+  "uqshl     z17.h, p0/m, z17.h, #2     \n" /* G0 */ \
+  "uqshl     z18.h, p0/m, z18.h, #2     \n" /* R0 */ \
+  "uqshl     z20.h, p0/m, z20.h, #2     \n" /* B1 */ \
+  "uqshl     z21.h, p0/m, z21.h, #2     \n" /* G1 */ \
+  "uqshl     z22.h, p0/m, z22.h, #2     \n" /* R1 */
+
+void I444ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  uint64_t vl;
+  asm volatile(
+      "cnth     %[vl]                                   \n"
+      "ptrue    p0.b                                    \n"  //
+      YUVTORGB_SVE_SETUP
+      "dup      z19.b, #255                             \n"  // Alpha
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "b.lt     2f                                      \n"
+
+      // Run bulk of computation with an all-true predicate to avoid predicate
+      // generation overhead.
+      "ptrue    p1.h                                    \n"
+      "1:                                               \n"  //
+      READYUV444_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "subs     %w[width], %w[width], %w[vl]            \n"
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+      "add      %[dst_argb], %[dst_argb], %[vl], lsl #2 \n"
+      "b.ge     1b                                      \n"
+
+      "2:                                               \n"
+      "adds     %w[width], %w[width], %w[vl]            \n"
+      "b.eq     99f                                     \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt  p1.h, wzr, %w[width]                    \n"  //
+      READYUV444_SVE I4XXTORGB_SVE RGBTOARGB8_SVE
+      "st2h     {z16.h, z17.h}, p1, [%[dst_argb]]       \n"
+
+      "99:                                              \n"
+      : [src_y] "+r"(src_y),                               // %[src_y]
+        [src_u] "+r"(src_u),                               // %[src_u]
+        [src_v] "+r"(src_v),                               // %[src_v]
+        [dst_argb] "+r"(dst_argb),                         // %[dst_argb]
+        [width] "+r"(width),                               // %[width]
+        [vl] "=&r"(vl)                                     // %[vl]
+      : [kUVCoeff] "r"(&yuvconstants->kUVCoeff),           // %[kUVCoeff]
+        [kRGBCoeffBias] "r"(&yuvconstants->kRGBCoeffBias)  // %[kRGBCoeffBias]
+      : "cc", "memory", YUVTORGB_SVE_REGS);
+}
+
+void I400ToARGBRow_SVE2(const uint8_t* src_y,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I400ToARGBRow_SVE_SC(src_y, dst_argb, yuvconstants, width);
+}
+
+void I422ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I422ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void I422ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_u,
+                         const uint8_t* src_v,
+                         uint8_t* dst_argb,
+                         const struct YuvConstants* yuvconstants,
+                         int width) {
+  I422ToRGB24Row_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void I422ToRGB565Row_SVE2(const uint8_t* src_y,
+                          const uint8_t* src_u,
+                          const uint8_t* src_v,
+                          uint8_t* dst_rgb565,
+                          const struct YuvConstants* yuvconstants,
+                          int width) {
+  I422ToRGB565Row_SVE_SC(src_y, src_u, src_v, dst_rgb565, yuvconstants, width);
+}
+
+void I422ToARGB1555Row_SVE2(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            uint8_t* dst_argb1555,
+                            const struct YuvConstants* yuvconstants,
+                            int width) {
+  I422ToARGB1555Row_SVE_SC(src_y, src_u, src_v, dst_argb1555, yuvconstants,
+                           width);
+}
+
+void I422ToARGB4444Row_SVE2(const uint8_t* src_y,
+                            const uint8_t* src_u,
+                            const uint8_t* src_v,
+                            uint8_t* dst_argb4444,
+                            const struct YuvConstants* yuvconstants,
+                            int width) {
+  I422ToARGB4444Row_SVE_SC(src_y, src_u, src_v, dst_argb4444, yuvconstants,
+                           width);
+}
+
+void I422ToRGBARow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_u,
+                        const uint8_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I422ToRGBARow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void I422AlphaToARGBRow_SVE2(const uint8_t* src_y,
+                             const uint8_t* src_u,
+                             const uint8_t* src_v,
+                             const uint8_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  I422AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+void I444AlphaToARGBRow_SVE2(const uint8_t* src_y,
+                             const uint8_t* src_u,
+                             const uint8_t* src_v,
+                             const uint8_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  I444AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+void NV12ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  NV12ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+void NV21ToARGBRow_SVE2(const uint8_t* src_y,
+                        const uint8_t* src_vu,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  NV21ToARGBRow_SVE_SC(src_y, src_vu, dst_argb, yuvconstants, width);
+}
+
+void NV12ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_uv,
+                         uint8_t* dst_rgb24,
+                         const struct YuvConstants* yuvconstants,
+                         int width) {
+  NV12ToRGB24Row_SVE_SC(src_y, src_uv, dst_rgb24, yuvconstants, width);
+}
+
+void NV21ToRGB24Row_SVE2(const uint8_t* src_y,
+                         const uint8_t* src_vu,
+                         uint8_t* dst_rgb24,
+                         const struct YuvConstants* yuvconstants,
+                         int width) {
+  NV21ToRGB24Row_SVE_SC(src_y, src_vu, dst_rgb24, yuvconstants, width);
+}
+
+// Dot-product constants are stored as four-tuples with the two innermost
+// elements flipped to account for the interleaving nature of the widening
+// addition instructions.
+
+// RGB to BT601 coefficients
+// UB   0.875 coefficient = 112
+// UG -0.5781 coefficient = -74
+// UR -0.2969 coefficient = -38
+// VB -0.1406 coefficient = -18
+// VG -0.7344 coefficient = -94
+// VR   0.875 coefficient = 112
+
+// SVE constants are not negated
+static const int16_t kARGBToUVCoefficients[] = {
+    // UB, -UR, -UG, 0, -VB, VR, -VG, 0
+    112, -38, -74, 0, -18, 112, -94, 0,
+};
+
+static const int16_t kRGBAToUVCoefficients[] = {
+    // 0, -UG, UB, -UR, 0, -VG, -VB, VR
+    0, -74, 112, -38, 0, -94, -18, 112,
+};
+
+static const int16_t kBGRAToUVCoefficients[] = {
+    // 0, -UG, -UR, UB, 0, -VG, VR, -VB
+    0, -74, -38, 112, 0, -94, 112, -18,
+};
+
+static const int16_t kABGRToUVCoefficients[] = {
+    // -UR, UB, -UG, 0, VR, -VB, -VG, 0
+    -38, 112, -74, 0, 112, -18, -94, 0,
+};
+
+// RGB to JPEG coefficients
+// UB  0.500    coefficient = 128
+// UG -0.33126  coefficient = -85
+// UR -0.16874  coefficient = -43
+// VB -0.08131  coefficient = -21
+// VG -0.41869  coefficient = -107
+// VR 0.500     coefficient = 128
+
+static const int16_t kARGBToUVJCoefficients[] = {
+    // UB, -UR, -UG, 0, -VB, VR, -VG, 0
+    128, -43, -85, 0, -21, 128, -107, 0,
+};
+
+static const int16_t kABGRToUVJCoefficients[] = {
+    // -UR, UB, -UG, 0, VR, -VB, -VG, 0
+    -43, 128, -85, 0, 128, -21, -107, 0,
+};
+
+static void ARGBToUVMatrixRow_SVE2(const uint8_t* src_argb,
+                                   int src_stride_argb,
+                                   uint8_t* dst_u,
+                                   uint8_t* dst_v,
+                                   int width,
+                                   const int16_t* uvconstants) {
+  const uint8_t* src_argb_1 = src_argb + src_stride_argb;
+  uint64_t vl;
+  asm volatile(
+      "ptrue    p0.b                                \n"
+      "ld1rd    {z24.d}, p0/z, [%[uvconstants]]     \n"
+      "ld1rd    {z25.d}, p0/z, [%[uvconstants], #8] \n"
+      "mov      z26.h, #0x8000                      \n"  // 128.0 (0x8000)
+      "cntb     %[vl]                               \n"
+      "subs     %w[width], %w[width], %w[vl]        \n"
+      "b.lt     2f                                  \n"
+
+      // Process 4x vectors from each input row per iteration.
+      // Cannot use predication here due to unrolling.
+      "1:                                           \n"  // e.g.
+      "ld1b     {z0.b}, p0/z, [%[src0], #0, mul vl] \n"  // bgrabgra
+      "ld1b     {z4.b}, p0/z, [%[src1], #0, mul vl] \n"  // bgrabgra
+      "ld1b     {z1.b}, p0/z, [%[src0], #1, mul vl] \n"  // bgrabgra
+      "ld1b     {z5.b}, p0/z, [%[src1], #1, mul vl] \n"  // bgrabgra
+      "ld1b     {z2.b}, p0/z, [%[src0], #2, mul vl] \n"  // bgrabgra
+      "ld1b     {z6.b}, p0/z, [%[src1], #2, mul vl] \n"  // bgrabgra
+      "ld1b     {z3.b}, p0/z, [%[src0], #3, mul vl] \n"  // bgrabgra
+      "ld1b     {z7.b}, p0/z, [%[src1], #3, mul vl] \n"  // bgrabgra
+      "incb     %[src0], all, mul #4                \n"
+      "incb     %[src1], all, mul #4                \n"
+
+      "uaddlb   z16.h, z0.b, z4.b                   \n"  // brbrbrbr
+      "uaddlt   z17.h, z0.b, z4.b                   \n"  // gagagaga
+      "uaddlb   z18.h, z1.b, z5.b                   \n"  // brbrbrbr
+      "uaddlt   z19.h, z1.b, z5.b                   \n"  // gagagaga
+      "uaddlb   z20.h, z2.b, z6.b                   \n"  // brbrbrbr
+      "uaddlt   z21.h, z2.b, z6.b                   \n"  // gagagaga
+      "uaddlb   z22.h, z3.b, z7.b                   \n"  // brbrbrbr
+      "uaddlt   z23.h, z3.b, z7.b                   \n"  // gagagaga
+
+      "trn1     z0.s, z16.s, z17.s                  \n"  // brgabgra
+      "trn2     z1.s, z16.s, z17.s                  \n"  // brgabgra
+      "trn1     z2.s, z18.s, z19.s                  \n"  // brgabgra
+      "trn2     z3.s, z18.s, z19.s                  \n"  // brgabgra
+      "trn1     z4.s, z20.s, z21.s                  \n"  // brgabgra
+      "trn2     z5.s, z20.s, z21.s                  \n"  // brgabgra
+      "trn1     z6.s, z22.s, z23.s                  \n"  // brgabgra
+      "trn2     z7.s, z22.s, z23.s                  \n"  // brgabgra
+
+      "subs     %w[width], %w[width], %w[vl]        \n"  // 4*VL per loop
+
+      "add      z0.h, p0/m, z0.h, z1.h              \n"  // brgabrga
+      "add      z2.h, p0/m, z2.h, z3.h              \n"  // brgabrga
+      "add      z4.h, p0/m, z4.h, z5.h              \n"  // brgabrga
+      "add      z6.h, p0/m, z6.h, z7.h              \n"  // brgabrga
+
+      "urshr    z0.h, p0/m, z0.h, #2                \n"  // brgabrga
+      "urshr    z2.h, p0/m, z2.h, #2                \n"  // brgabrga
+      "urshr    z4.h, p0/m, z4.h, #2                \n"  // brgabrga
+      "urshr    z6.h, p0/m, z6.h, #2                \n"  // brgabrga
+
+      "movi     v16.8h, #0                          \n"
+      "movi     v17.8h, #0                          \n"
+      "movi     v18.8h, #0                          \n"
+      "movi     v19.8h, #0                          \n"
+
+      "movi     v20.8h, #0                          \n"
+      "movi     v21.8h, #0                          \n"
+      "movi     v22.8h, #0                          \n"
+      "movi     v23.8h, #0                          \n"
+
+      "sdot     z16.d, z0.h, z24.h                  \n"  // UUxxxxxx
+      "sdot     z17.d, z2.h, z24.h                  \n"  // UUxxxxxx
+      "sdot     z18.d, z4.h, z24.h                  \n"  // UUxxxxxx
+      "sdot     z19.d, z6.h, z24.h                  \n"  // UUxxxxxx
+
+      "sdot     z20.d, z0.h, z25.h                  \n"  // VVxxxxxx
+      "sdot     z21.d, z2.h, z25.h                  \n"  // VVxxxxxx
+      "sdot     z22.d, z4.h, z25.h                  \n"  // VVxxxxxx
+      "sdot     z23.d, z6.h, z25.h                  \n"  // VVxxxxxx
+
+      "uzp1     z16.s, z16.s, z17.s                 \n"  // UUxx
+      "uzp1     z18.s, z18.s, z19.s                 \n"  // UUxx
+      "uzp1     z20.s, z20.s, z21.s                 \n"  // VVxx
+      "uzp1     z22.s, z22.s, z23.s                 \n"  // VVxx
+
+      "uzp1     z16.h, z16.h, z18.h                 \n"  // UU
+      "uzp1     z20.h, z20.h, z22.h                 \n"  // VV
+
+      "addhnb   z16.b, z16.h, z26.h                 \n"  // U
+      "addhnb   z20.b, z20.h, z26.h                 \n"  // V
+
+      "st1b     {z16.h}, p0, [%[dst_u]]             \n"  // U
+      "st1b     {z20.h}, p0, [%[dst_v]]             \n"  // V
+      "inch     %[dst_u]                            \n"
+      "inch     %[dst_v]                            \n"
+
+      "b.ge     1b                                  \n"
+
+      "2:                                           \n"
+      "adds     %w[width], %w[width], %w[vl]        \n"  // VL per loop
+      "b.le     99f                                 \n"
+
+      // Process remaining pixels from each input row.
+      // Use predication to do one vector from each input array, so may loop up
+      // to three iterations.
+      "cntw     %x[vl]                              \n"
+
+      "3:                                           \n"
+      "whilelt  p1.s, wzr, %w[width]                \n"
+      "ld1d     {z0.d}, p1/z, [%[src0]]             \n"  // bgrabgra
+      "ld1d     {z4.d}, p1/z, [%[src1]]             \n"  // bgrabgra
+      "incb     %[src0]                             \n"
+      "incb     %[src1]                             \n"
+
+      "uaddlb   z16.h, z0.b, z4.b                   \n"  // brbrbrbr
+      "uaddlt   z17.h, z0.b, z4.b                   \n"  // gagagaga
+
+      "trn1     z0.s, z16.s, z17.s                  \n"  // brgabgra
+      "trn2     z1.s, z16.s, z17.s                  \n"  // brgabgra
+
+      "add      z0.h, p0/m, z0.h, z1.h              \n"  // brgabrga
+
+      "urshr    z0.h, p0/m, z0.h, #2                \n"  // brgabrga
+
+      "subs     %w[width], %w[width], %w[vl]        \n"  // VL per loop
+
+      "movi     v16.8h, #0                          \n"
+      "movi     v20.8h, #0                          \n"
+
+      "sdot     z16.d, z0.h, z24.h                  \n"
+      "sdot     z20.d, z0.h, z25.h                  \n"
+
+      "addhnb   z16.b, z16.h, z26.h                 \n"  // U
+      "addhnb   z20.b, z20.h, z26.h                 \n"  // V
+
+      "st1b     {z16.d}, p0, [%[dst_u]]             \n"  // U
+      "st1b     {z20.d}, p0, [%[dst_v]]             \n"  // V
+      "incd     %[dst_u]                            \n"
+      "incd     %[dst_v]                            \n"
+      "b.gt     3b                                  \n"
+
+      "99:                                          \n"
+      : [src0] "+r"(src_argb),    // %[src0]
+        [src1] "+r"(src_argb_1),  // %[src1]
+        [dst_u] "+r"(dst_u),      // %[dst_u]
+        [dst_v] "+r"(dst_v),      // %[dst_v]
+        [width] "+r"(width),      // %[width]
+        [vl] "=&r"(vl)            // %[vl]
+      : [uvconstants] "r"(uvconstants)
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z16",
+        "z17", "z18", "z19", "z20", "z21", "z22", "z23", "z24", "z25", "z26",
+        "p0");
+}
+
+void ARGBToUVRow_SVE2(const uint8_t* src_argb,
+                      int src_stride_argb,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_SVE2(src_argb, src_stride_argb, dst_u, dst_v, width,
+                         kARGBToUVCoefficients);
+}
+
+void ARGBToUVJRow_SVE2(const uint8_t* src_argb,
+                       int src_stride_argb,
+                       uint8_t* dst_u,
+                       uint8_t* dst_v,
+                       int width) {
+  ARGBToUVMatrixRow_SVE2(src_argb, src_stride_argb, dst_u, dst_v, width,
+                         kARGBToUVJCoefficients);
+}
+
+void ABGRToUVJRow_SVE2(const uint8_t* src_abgr,
+                       int src_stride_abgr,
+                       uint8_t* dst_uj,
+                       uint8_t* dst_vj,
+                       int width) {
+  ARGBToUVMatrixRow_SVE2(src_abgr, src_stride_abgr, dst_uj, dst_vj, width,
+                         kABGRToUVJCoefficients);
+}
+
+void BGRAToUVRow_SVE2(const uint8_t* src_bgra,
+                      int src_stride_bgra,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_SVE2(src_bgra, src_stride_bgra, dst_u, dst_v, width,
+                         kBGRAToUVCoefficients);
+}
+
+void ABGRToUVRow_SVE2(const uint8_t* src_abgr,
+                      int src_stride_abgr,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_SVE2(src_abgr, src_stride_abgr, dst_u, dst_v, width,
+                         kABGRToUVCoefficients);
+}
+
+void RGBAToUVRow_SVE2(const uint8_t* src_rgba,
+                      int src_stride_rgba,
+                      uint8_t* dst_u,
+                      uint8_t* dst_v,
+                      int width) {
+  ARGBToUVMatrixRow_SVE2(src_rgba, src_stride_rgba, dst_u, dst_v, width,
+                         kRGBAToUVCoefficients);
+}
+
+#define ARGBTORGB565_SVE                    \
+  /* Inputs:                                \
+   * z0: rrrrrxxxbbbbbxxx                   \
+   * z1: xxxxxxxxggggggxx                   \
+   * z3: 0000000000000011 (3, 0, 3, 0, ...) \
+   * z4: 0000011111100000                   \
+   */                                       \
+  "lsr     z0.b, p0/m, z0.b, z3.b       \n" \
+  "lsl     z1.h, z1.h, #3               \n" \
+  "bsl     z1.d, z1.d, z0.d, z4.d       \n"
+
+void ARGBToRGB565Row_SVE2(const uint8_t* src_argb,
+                          uint8_t* dst_rgb,
+                          int width) {
+  unsigned bsl_mask = 0x7e0;
+  uint64_t vl;
+  width *= 2;
+  asm volatile(
+      "mov     z3.h, #3                     \n"
+      "dup     z4.h, %w[bsl_mask]           \n"
+
+      "cntb    %[vl]                        \n"
+      "subs    %w[width], %w[width], %w[vl] \n"
+      "b.lt    2f                           \n"
+
+      "ptrue   p0.b                         \n"
+      "1:                                   \n"
+      "ld2b    {z0.b, z1.b}, p0/z, [%[src]] \n"  // BR, GA
+      "incb    %[src], all, mul #2          \n"
+      "subs    %w[width], %w[width], %w[vl] \n"  //
+      ARGBTORGB565_SVE
+      "st1b    {z1.b}, p0, [%[dst]]         \n"
+      "incb    %[dst]                       \n"
+      "b.ge    1b                           \n"
+
+      "2:                                   \n"
+      "adds    %w[width], %w[width], %w[vl] \n"
+      "b.eq    99f                          \n"
+
+      "whilelt p0.b, wzr, %w[width]         \n"
+      "ld2b    {z0.b, z1.b}, p0/z, [%[src]] \n"  // BR, GA
+      ARGBTORGB565_SVE
+      "st1b    {z1.b}, p0, [%[dst]]         \n"
+
+      "99:                                  \n"
+      : [src] "+r"(src_argb),     // %[src]
+        [dst] "+r"(dst_rgb),      // %[dst]
+        [width] "+r"(width),      // %[width]
+        [vl] "=&r"(vl)            // %[vl]
+      : [bsl_mask] "r"(bsl_mask)  // %[bsl_mask]
+      : "cc", "memory", "z0", "z1", "z3", "z4", "p0");
+}
+
+void ARGBToRGB565DitherRow_SVE2(const uint8_t* src_argb,
+                                uint8_t* dst_rgb,
+                                uint32_t dither4,
+                                int width) {
+  unsigned bsl_mask = 0x7e0;
+  uint64_t vl;
+  width *= 2;
+  asm volatile(
+      "mov     z3.h, #3                     \n"
+      "dup     z4.h, %w[bsl_mask]           \n"
+      "dup     z2.s, %w[dither4]            \n"
+      "zip1    z2.b, z2.b, z2.b             \n"
+
+      "cntb    %[vl]                        \n"
+      "subs    %w[width], %w[width], %w[vl] \n"
+      "b.lt    2f                           \n"
+
+      "ptrue   p0.b                         \n"
+      "1:                                   \n"
+      "ld2b    {z0.b, z1.b}, p0/z, [%[src]] \n"  // BR, GA
+      "incb    %[src], all, mul #2          \n"
+      "uqadd   z0.b, z0.b, z2.b             \n"
+      "uqadd   z1.b, z1.b, z2.b             \n"
+      "subs    %w[width], %w[width], %w[vl] \n"  //
+      ARGBTORGB565_SVE
+      "st1b    {z1.b}, p0, [%[dst]]         \n"
+      "incb    %[dst]                       \n"
+      "b.ge    1b                           \n"
+
+      "2:                                   \n"
+      "adds    %w[width], %w[width], %w[vl] \n"
+      "b.eq    99f                          \n"
+
+      "whilelt p0.b, wzr, %w[width]         \n"
+      "ld2b    {z0.b, z1.b}, p0/z, [%[src]] \n"  // BR, GA
+      "uqadd   z0.b, z0.b, z2.b             \n"
+      "uqadd   z1.b, z1.b, z2.b             \n"  //
+      ARGBTORGB565_SVE
+      "st1b    {z1.b}, p0, [%[dst]]         \n"
+
+      "99:                                  \n"
+      : [src] "+r"(src_argb),      // %[src]
+        [dst] "+r"(dst_rgb),       // %[dst]
+        [width] "+r"(width),       // %[width]
+        [vl] "=&r"(vl)             // %[vl]
+      : [bsl_mask] "r"(bsl_mask),  // %[bsl_mask]
+        [dither4] "r"(dither4)     // %[dither4]
+      : "cc", "memory", "z0", "z1", "z3", "z4", "p0");
+}
+
+#define ARGB1555TOARGB                                        \
+  /* Input: z1/z3.h = arrrrrgggggbbbbb */                     \
+  "lsl     z0.h, z1.h, #3          \n" /* rrrgggggbbbbb000 */ \
+  "lsl     z2.h, z3.h, #3          \n" /* rrrgggggbbbbb000 */ \
+  "asr     z1.h, z1.h, #7          \n" /* aaaaaaaarrrrrggg */ \
+  "asr     z3.h, z3.h, #7          \n" /* aaaaaaaarrrrrggg */ \
+  "lsl     z0.b, p0/m, z0.b, z4.b  \n" /* ggggg000bbbbb000 */ \
+  "lsl     z2.b, p0/m, z2.b, z4.b  \n" /* ggggg000bbbbb000 */ \
+  "sri     z1.b, z1.b, #5          \n" /* aaaaaaaarrrrrrrr */ \
+  "sri     z3.b, z3.b, #5          \n" /* aaaaaaaarrrrrrrr */ \
+  "sri     z0.b, z0.b, #5          \n" /* ggggggggbbbbbbbb */ \
+  "sri     z2.b, z2.b, #5          \n" /* ggggggggbbbbbbbb */
+
+void ARGB1555ToARGBRow_SVE2(const uint8_t* src_argb1555,
+                            uint8_t* dst_argb,
+                            int width) {
+  uint64_t vl;
+  asm volatile(
+      "mov     z4.h, #0x0300                           \n"
+      "ptrue   p0.b                                    \n"
+
+      "cnth    %x[vl]                                  \n"
+      "subs    %w[width], %w[width], %w[vl], lsl #1    \n"
+      "b.lt    2f                                      \n"
+
+      "1:                                              \n"
+      "ld1h    {z1.h}, p0/z, [%[src]]                  \n"
+      "ld1h    {z3.h}, p0/z, [%[src], #1, mul vl]      \n"
+      "incb    %[src], all, mul #2                     \n"  //
+      ARGB1555TOARGB
+      "subs    %w[width], %w[width], %w[vl], lsl #1    \n"
+      "st2h    {z0.h, z1.h}, p0, [%[dst]]              \n"
+      "st2h    {z2.h, z3.h}, p0, [%[dst], #2, mul vl]  \n"
+      "incb    %[dst], all, mul #4                     \n"
+      "b.ge    1b                                      \n"
+
+      "2:                                              \n"
+      "adds    %w[width], %w[width], %w[vl], lsl #1    \n"
+      "b.eq    99f                                     \n"
+
+      "whilelt p1.h, wzr, %w[width]                    \n"
+      "whilelt p2.h, %w[vl], %w[width]                 \n"
+      "ld1h    {z1.h}, p1/z, [%[src]]                  \n"
+      "ld1h    {z3.h}, p2/z, [%[src], #1, mul vl]      \n"  //
+      ARGB1555TOARGB
+      "st2h    {z0.h, z1.h}, p1, [%[dst]]              \n"
+      "st2h    {z2.h, z3.h}, p2, [%[dst], #2, mul vl]  \n"
+
+      "99:                                             \n"
+      : [src] "+r"(src_argb1555),  // %[src]
+        [dst] "+r"(dst_argb),      // %[dst]
+        [width] "+r"(width),       // %[width]
+        [vl] "=&r"(vl)             // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "p0", "p1", "p2");
+}
+
+// clang-format off
+#define AYUVTOUV_SVE(zU0, zV0, zU1, zV1)                   /* e.g. */          \
+  "ld2h     {z0.h, z1.h}, p0/z, [%[src0]]              \n" /* VUVU.. YAYA.. */ \
+  "ld2h     {z1.h, z2.h}, p1/z, [%[src0], #2, mul vl]  \n" /* VUVU.. YAYA.. */ \
+  "ld2h     {z2.h, z3.h}, p0/z, [%[src1]]              \n" /* VUVU.. YAYA.. */ \
+  "ld2h     {z3.h, z4.h}, p1/z, [%[src1], #2, mul vl]  \n" /* VUVU.. YAYA.. */ \
+  "incb     %[src0], all, mul #4                       \n"                     \
+  "incb     %[src1], all, mul #4                       \n"                     \
+  "uaddlb   z4.h, z0.b, z2.b                           \n" /* V */             \
+  "uaddlt   z5.h, z0.b, z2.b                           \n" /* U */             \
+  "uaddlb   z6.h, z1.b, z3.b                           \n" /* V */             \
+  "uaddlt   z7.h, z1.b, z3.b                           \n" /* U */             \
+  "addp   " #zU0 ".h, p0/m, " #zU0 ".h, " #zV0 ".h     \n" /* UV */            \
+  "addp   " #zU1 ".h, p1/m, " #zU1 ".h, " #zV1 ".h     \n" /* UV */            \
+  "subs     %w[width], %w[width], %w[vl]               \n"                     \
+  "urshr  " #zU0 ".h, p0/m, " #zU0 ".h, #2             \n" /* U0V0 */          \
+  "urshr  " #zU1 ".h, p1/m, " #zU1 ".h, #2             \n" /* U0V0 */          \
+  "st1b     {" #zU0 ".h}, p0, [%[dst]]                 \n"                     \
+  "st1b     {" #zU1 ".h}, p1, [%[dst], #1, mul vl]     \n"                     \
+  "incb     %[dst]                                     \n"
+// clang-format on
+
+// Filter 2 rows of AYUV UV's (444) into UV (420).
+// AYUV is VUYA in memory.  UV for NV12 is UV order in memory.
+void AYUVToUVRow_SVE2(const uint8_t* src_ayuv,
+                      int src_stride_ayuv,
+                      uint8_t* dst_uv,
+                      int width) {
+  // Output a row of UV values, filtering 2x2 rows of AYUV.
+  const uint8_t* src_ayuv1 = src_ayuv + src_stride_ayuv;
+  int vl;
+  asm volatile (
+      "cntb    %x[vl]                            \n"
+      "subs    %w[width], %w[width], %w[vl]      \n"
+      "b.lt    2f                                \n"
+
+      "ptrue   p0.h                              \n"
+      "ptrue   p1.h                              \n"
+      "1:                                        \n"
+      AYUVTOUV_SVE(z5, z4, z7, z6)
+      "b.ge    1b                                \n"
+
+      "2:                                        \n"
+      "adds    %w[width], %w[width], %w[vl]      \n"
+      "b.eq    99f                               \n"
+
+      "cnth    %x[vl]                            \n"
+      "whilelt p0.h, wzr, %w[width]              \n" // first row
+      "whilelt p1.h, %w[vl], %w[width]           \n" // second row
+      AYUVTOUV_SVE(z5, z4, z7, z6)
+
+      "99:                                       \n"
+      : [src0]"+r"(src_ayuv),   // %[src0]
+        [src1]"+r"(src_ayuv1),  // %[src1]
+        [dst]"+r"(dst_uv),      // %[dst]
+        [width]"+r"(width),     // %[width]
+        [vl]"=&r"(vl)           // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0",
+        "p1");
+}
+
+// Filter 2 rows of AYUV UV's (444) into VU (420).
+void AYUVToVURow_SVE2(const uint8_t* src_ayuv,
+                      int src_stride_ayuv,
+                      uint8_t* dst_vu,
+                      int width) {
+  // Output a row of VU values, filtering 2x2 rows of AYUV.
+  const uint8_t* src_ayuv1 = src_ayuv + src_stride_ayuv;
+  int vl;
+  asm volatile (
+      "cntb    %x[vl]                            \n"
+      "cmp     %w[width], %w[vl]                 \n"
+      "subs    %w[width], %w[width], %w[vl]      \n"
+      "b.lt    2f                                \n"
+
+      "ptrue   p0.h                              \n"
+      "ptrue   p1.h                              \n"
+      "1:                                        \n"
+      AYUVTOUV_SVE(z4, z5, z6, z7)
+      "b.ge    1b                                \n"
+
+      "2:                                        \n"
+      "adds    %w[width], %w[width], %w[vl]      \n"
+      "b.eq    99f                               \n"
+
+      "cnth    %x[vl]                            \n"
+      "whilelt p0.h, wzr, %w[width]              \n" // first row
+      "whilelt p1.h, %w[vl], %w[width]           \n" // second row
+      AYUVTOUV_SVE(z4, z5, z6, z7)
+
+      "99:                                       \n"
+      : [src0]"+r"(src_ayuv),   // %[src0]
+        [src1]"+r"(src_ayuv1),  // %[src1]
+        [dst]"+r"(dst_vu),      // %[dst]
+        [width]"+r"(width),     // %[width]
+        [vl]"=&r"(vl)           // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0",
+        "p1");
+}
+
+void YUY2ToARGBRow_SVE2(const uint8_t* src_yuy2,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  YUY2ToARGBRow_SVE_SC(src_yuy2, dst_argb, yuvconstants, width);
+}
+
+void UYVYToARGBRow_SVE2(const uint8_t* src_uyvy,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  UYVYToARGBRow_SVE_SC(src_uyvy, dst_argb, yuvconstants, width);
+}
+
+static inline void RAWToWXYZRow_SVE2(const uint8_t* src_raw,
+                                     uint8_t* dst_wxyz,
+                                     int width,
+                                     uint32_t idx_start,
+                                     uint32_t idx_step,
+                                     uint32_t alpha) {
+  uint32_t vl;
+  asm("cntw %x0" : "=r"(vl));
+  uint32_t vl_mul3 = vl * 3;
+  uint32_t rem_mul3;
+  asm volatile(
+      "index   z31.s, %w[idx_start], %w[idx_step]        \n"
+      "dup     z30.s, %w[alpha]                          \n"
+      "subs    %w[width], %w[width], %w[vl], lsl #1      \n"
+      "b.lt    2f                                        \n"
+
+      // Run bulk of computation with the same predicates to avoid predicate
+      // generation overhead. We set up p1 to only load 3/4 of a vector.
+      "ptrue   p0.s                                      \n"
+      "whilelt p1.b, wzr, %w[vl_mul3]                    \n"
+      "1:                                                \n"
+      "ld1b    {z0.b}, p1/z, [%[src]]                    \n"
+      "add     %[src], %[src], %x[vl_mul3]               \n"
+      "ld1b    {z1.b}, p1/z, [%[src]]                    \n"
+      "add     %[src], %[src], %x[vl_mul3]               \n"
+      "tbl     z0.b, {z0.b}, z31.b                       \n"
+      "tbl     z1.b, {z1.b}, z31.b                       \n"
+      "subs    %w[width], %w[width], %w[vl], lsl #1      \n"
+      "orr     z0.d, z0.d, z30.d                         \n"
+      "orr     z1.d, z1.d, z30.d                         \n"
+      "st1w    {z0.s}, p0, [%[dst]]                      \n"
+      "st1w    {z1.s}, p0, [%[dst], #1, mul vl]          \n"
+      "incb    %[dst], all, mul #2                       \n"
+      "b.ge    1b                                        \n"
+
+      "2:                                                \n"
+      "adds     %w[width], %w[width], %w[vl], lsl #1     \n"
+      "b.eq     99f                                      \n"
+
+      // Calculate a pair of predicates for the final iteration to deal with
+      // the tail.
+      "3:                                                \n"
+      "add     %w[rem_mul3], %w[width], %w[width], lsl #1 \n"
+      "whilelt p0.s, wzr, %w[width]                      \n"
+      "whilelt p1.b, wzr, %w[rem_mul3]                    \n"
+      "ld1b    {z0.b}, p1/z, [%[src]]                    \n"
+      "add     %[src], %[src], %x[vl_mul3]               \n"
+      "tbl     z0.b, {z0.b}, z31.b                       \n"
+      "subs    %w[width], %w[width], %w[vl]              \n"
+      "orr     z0.d, z0.d, z30.d                         \n"
+      "st1w    {z0.s}, p0, [%[dst]]                      \n"
+      "incb    %[dst]                                    \n"
+      "b.gt    3b                                        \n"
+
+      "99:                                               \n"
+      : [src] "+r"(src_raw),         // %[src]
+        [dst] "+r"(dst_wxyz),        // %[dst]
+        [width] "+r"(width),         // %[width]
+        [vl_mul3] "+r"(vl_mul3),     // %[vl_mul3]
+        [rem_mul3] "=&r"(rem_mul3)   // %[rem_mul3]
+      : [idx_start] "r"(idx_start),  // %[idx_start]
+        [idx_step] "r"(idx_step),    // %[idx_step]
+        [alpha] "r"(alpha),          // %[alpha]
+        [vl] "r"(vl)                 // %[vl]
+      : "cc", "memory", "z0", "z1", "z30", "z31", "p0", "p1");
+}
+
+void RAWToARGBRow_SVE2(const uint8_t* src_raw, uint8_t* dst_argb, int width) {
+  RAWToWXYZRow_SVE2(src_raw, dst_argb, width, 0xff000102U, 0x00030303U,
+                    0xff000000U);
+}
+
+void RAWToRGBARow_SVE2(const uint8_t* src_raw, uint8_t* dst_rgba, int width) {
+  RAWToWXYZRow_SVE2(src_raw, dst_rgba, width, 0x000102ffU, 0x03030300U,
+                    0x000000ffU);
+}
+
+void RGB24ToARGBRow_SVE2(const uint8_t* src_rgb24,
+                         uint8_t* dst_argb,
+                         int width) {
+  RAWToWXYZRow_SVE2(src_rgb24, dst_argb, width, 0xff020100U, 0x00030303U,
+                    0xff000000U);
+}
+
+static const uint8_t kRAWToRGB24Indices[] = {
+    2,   1,   0,   5,   4,   3,   8,   7,   6,   11,  10,  9,   14,  13,  12,
+    17,  16,  15,  20,  19,  18,  23,  22,  21,  26,  25,  24,  29,  28,  27,
+    32,  31,  30,  35,  34,  33,  38,  37,  36,  41,  40,  39,  44,  43,  42,
+    47,  46,  45,  50,  49,  48,  53,  52,  51,  56,  55,  54,  59,  58,  57,
+    62,  61,  60,  65,  64,  63,  68,  67,  66,  71,  70,  69,  74,  73,  72,
+    77,  76,  75,  80,  79,  78,  83,  82,  81,  86,  85,  84,  89,  88,  87,
+    92,  91,  90,  95,  94,  93,  98,  97,  96,  101, 100, 99,  104, 103, 102,
+    107, 106, 105, 110, 109, 108, 113, 112, 111, 116, 115, 114, 119, 118, 117,
+    122, 121, 120, 125, 124, 123, 128, 127, 126, 131, 130, 129, 134, 133, 132,
+    137, 136, 135, 140, 139, 138, 143, 142, 141, 146, 145, 144, 149, 148, 147,
+    152, 151, 150, 155, 154, 153, 158, 157, 156, 161, 160, 159, 164, 163, 162,
+    167, 166, 165, 170, 169, 168, 173, 172, 171, 176, 175, 174, 179, 178, 177,
+    182, 181, 180, 185, 184, 183, 188, 187, 186, 191, 190, 189, 194, 193, 192,
+    197, 196, 195, 200, 199, 198, 203, 202, 201, 206, 205, 204, 209, 208, 207,
+    212, 211, 210, 215, 214, 213, 218, 217, 216, 221, 220, 219, 224, 223, 222,
+    227, 226, 225, 230, 229, 228, 233, 232, 231, 236, 235, 234, 239, 238, 237,
+    242, 241, 240, 245, 244, 243, 248, 247, 246, 251, 250, 249, 254, 253, 252};
+
+void RAWToRGB24Row_SVE2(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) {
+  // width is in elements, convert to bytes.
+  width *= 3;
+  // we use the mul3 predicate pattern throughout to use the largest multiple
+  // of three number of lanes, for instance with a vector length of 16 bytes
+  // only the first 15 bytes will be used for load/store instructions.
+  uint32_t vl;
+  asm volatile(
+      "cntb    %x[vl], mul3                              \n"
+      "ptrue   p0.b, mul3                                \n"
+      "ld1b    {z31.b}, p0/z, [%[kIndices]]              \n"
+      "subs    %w[width], %w[width], %w[vl]              \n"
+      "b.lt    2f                                        \n"
+
+      // Run bulk of computation with the same predicate to avoid predicate
+      // generation overhead.
+      "1:                                                \n"
+      "ld1b    {z0.b}, p0/z, [%[src]]                    \n"
+      "add     %[src], %[src], %x[vl]                    \n"
+      "tbl     z0.b, {z0.b}, z31.b                       \n"
+      "subs    %w[width], %w[width], %w[vl]              \n"
+      "st1b    {z0.b}, p0, [%[dst]]                      \n"
+      "add     %[dst], %[dst], %x[vl]                    \n"
+      "b.ge    1b                                        \n"
+
+      "2:                                                \n"
+      "adds    %w[width], %w[width], %w[vl]              \n"
+      "b.eq    99f                                       \n"
+
+      // Calculate a predicate for the final iteration to deal with the tail.
+      "whilelt p0.b, wzr, %w[width]                      \n"
+      "ld1b    {z0.b}, p0/z, [%[src]]                    \n"
+      "tbl     z0.b, {z0.b}, z31.b                       \n"
+      "st1b    {z0.b}, p0, [%[dst]]                      \n"
+
+      "99:                                               \n"
+      : [src] "+r"(src_raw),                // %[src]
+        [dst] "+r"(dst_rgb24),              // %[dst]
+        [width] "+r"(width),                // %[width]
+        [vl] "=&r"(vl)                      // %[vl]
+      : [kIndices] "r"(kRAWToRGB24Indices)  // %[kIndices]
+      : "cc", "memory", "z0", "z31", "p0");
+}
+
+static inline void ARGBToXYZRow_SVE2(const uint8_t* src_argb,
+                                     uint8_t* dst_xyz,
+                                     int width,
+                                     const uint8_t* indices) {
+  uint32_t vl;
+  asm("cntw %x0" : "=r"(vl));
+  uint32_t vl_mul3 = vl * 3;
+  uint32_t rem_mul3;
+  asm volatile(
+      "whilelt p1.b, wzr, %w[vl_mul3]                     \n"
+      "ld1b    {z31.b}, p1/z, [%[indices]]                \n"
+      "subs    %w[width], %w[width], %w[vl], lsl #1       \n"
+      "b.lt    2f                                         \n"
+
+      // Run bulk of computation with the same predicates to avoid predicate
+      // generation overhead. We set up p1 to only store 3/4 of a vector.
+      "ptrue   p0.s                                       \n"
+      "1:                                                 \n"
+      "ld1w    {z0.s}, p0/z, [%[src]]                     \n"
+      "ld1w    {z1.s}, p0/z, [%[src], #1, mul vl]         \n"
+      "incb    %[src], all, mul #2                        \n"
+      "tbl     z0.b, {z0.b}, z31.b                        \n"
+      "tbl     z1.b, {z1.b}, z31.b                        \n"
+      "subs    %w[width], %w[width], %w[vl], lsl #1       \n"
+      "st1b    {z0.b}, p1, [%[dst]]                       \n"
+      "add     %[dst], %[dst], %x[vl_mul3]                \n"
+      "st1b    {z1.b}, p1, [%[dst]]                       \n"
+      "add     %[dst], %[dst], %x[vl_mul3]                \n"
+      "b.ge    1b                                         \n"
+
+      "2:                                                 \n"
+      "adds    %w[width], %w[width], %w[vl], lsl #1       \n"
+      "b.eq    99f                                        \n"
+
+      // Calculate predicates for the final iteration to deal with the tail.
+      "add     %w[rem_mul3], %w[width], %w[width], lsl #1 \n"
+      "whilelt p0.s, wzr, %w[width]                       \n"
+      "whilelt p1.b, wzr, %w[rem_mul3]                    \n"
+      "whilelt p2.s, %w[vl], %w[width]                    \n"
+      "whilelt p3.b, %w[vl_mul3], %w[rem_mul3]            \n"
+      "ld1w    {z0.s}, p0/z, [%[src]]                     \n"
+      "ld1w    {z1.s}, p2/z, [%[src], #1, mul vl]         \n"
+      "tbl     z0.b, {z0.b}, z31.b                        \n"
+      "tbl     z1.b, {z1.b}, z31.b                        \n"
+      "st1b    {z0.b}, p1, [%[dst]]                       \n"
+      "add     %[dst], %[dst], %x[vl_mul3]                \n"
+      "st1b    {z1.b}, p3, [%[dst]]                       \n"
+
+      "99:                                                \n"
+      : [src] "+r"(src_argb),       // %[src]
+        [dst] "+r"(dst_xyz),        // %[dst]
+        [width] "+r"(width),        // %[width]
+        [rem_mul3] "=&r"(rem_mul3)  // %[rem_mul3]
+      : [indices] "r"(indices),     // %[indices]
+        [vl_mul3] "r"(vl_mul3),     // %[vl_mul3]
+        [vl] "r"(vl)                // %[vl]
+      : "cc", "memory", "z0", "z1", "z31", "p0", "p1", "p2", "p3");
+}
+
+static const uint8_t kARGBToRGB24RowIndices[] = {
+    0,   1,   2,   4,   5,   6,   8,   9,   10,  12,  13,  14,  16,  17,  18,
+    20,  21,  22,  24,  25,  26,  28,  29,  30,  32,  33,  34,  36,  37,  38,
+    40,  41,  42,  44,  45,  46,  48,  49,  50,  52,  53,  54,  56,  57,  58,
+    60,  61,  62,  64,  65,  66,  68,  69,  70,  72,  73,  74,  76,  77,  78,
+    80,  81,  82,  84,  85,  86,  88,  89,  90,  92,  93,  94,  96,  97,  98,
+    100, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 116, 117, 118,
+    120, 121, 122, 124, 125, 126, 128, 129, 130, 132, 133, 134, 136, 137, 138,
+    140, 141, 142, 144, 145, 146, 148, 149, 150, 152, 153, 154, 156, 157, 158,
+    160, 161, 162, 164, 165, 166, 168, 169, 170, 172, 173, 174, 176, 177, 178,
+    180, 181, 182, 184, 185, 186, 188, 189, 190, 192, 193, 194, 196, 197, 198,
+    200, 201, 202, 204, 205, 206, 208, 209, 210, 212, 213, 214, 216, 217, 218,
+    220, 221, 222, 224, 225, 226, 228, 229, 230, 232, 233, 234, 236, 237, 238,
+    240, 241, 242, 244, 245, 246, 248, 249, 250, 252, 253, 254,
+};
+
+static const uint8_t kARGBToRAWRowIndices[] = {
+    2,   1,   0,   6,   5,   4,   10,  9,   8,   14,  13,  12,  18,  17,  16,
+    22,  21,  20,  26,  25,  24,  30,  29,  28,  34,  33,  32,  38,  37,  36,
+    42,  41,  40,  46,  45,  44,  50,  49,  48,  54,  53,  52,  58,  57,  56,
+    62,  61,  60,  66,  65,  64,  70,  69,  68,  74,  73,  72,  78,  77,  76,
+    82,  81,  80,  86,  85,  84,  90,  89,  88,  94,  93,  92,  98,  97,  96,
+    102, 101, 100, 106, 105, 104, 110, 109, 108, 114, 113, 112, 118, 117, 116,
+    122, 121, 120, 126, 125, 124, 130, 129, 128, 134, 133, 132, 138, 137, 136,
+    142, 141, 140, 146, 145, 144, 150, 149, 148, 154, 153, 152, 158, 157, 156,
+    162, 161, 160, 166, 165, 164, 170, 169, 168, 174, 173, 172, 178, 177, 176,
+    182, 181, 180, 186, 185, 184, 190, 189, 188, 194, 193, 192, 198, 197, 196,
+    202, 201, 200, 206, 205, 204, 210, 209, 208, 214, 213, 212, 218, 217, 216,
+    222, 221, 220, 226, 225, 224, 230, 229, 228, 234, 233, 232, 238, 237, 236,
+    242, 241, 240, 246, 245, 244, 250, 249, 248, 254, 253, 252,
+};
+
+void ARGBToRGB24Row_SVE2(const uint8_t* src_argb, uint8_t* dst_rgb, int width) {
+  ARGBToXYZRow_SVE2(src_argb, dst_rgb, width, kARGBToRGB24RowIndices);
+}
+
+void ARGBToRAWRow_SVE2(const uint8_t* src_argb, uint8_t* dst_rgb, int width) {
+  ARGBToXYZRow_SVE2(src_argb, dst_rgb, width, kARGBToRAWRowIndices);
+}
+
+void DivideRow_16_SVE2(const uint16_t* src_y,
+                       uint16_t* dst_y,
+                       int scale,
+                       int width) {
+  uint64_t vl;
+  asm volatile(
+      "cnth   %x[vl]                                     \n"
+      "dup    z0.h, %w[scale]                            \n"
+      "subs   %w[width], %w[width], %w[vl], lsl #1       \n"
+      "b.le    2f                                        \n"
+
+      // Run bulk of computation with the same predicates to avoid predicate
+      // generation overhead.
+      "ptrue   p0.h                                      \n"
+      "1:                                                \n"
+      "ld1h   {z1.h}, p0/z, [%[src]]                     \n"
+      "ld1h   {z2.h}, p0/z, [%[src], #1, mul vl]         \n"
+      "incb   %[src], all, mul #2                        \n"
+      "umulh  z1.h, z1.h, z0.h                           \n"
+      "umulh  z2.h, z2.h, z0.h                           \n"
+      "subs   %w[width], %w[width], %w[vl], lsl #1       \n"
+      "st1h   {z1.h}, p0, [%[dst]]                       \n"
+      "st1h   {z2.h}, p0, [%[dst], #1, mul vl]           \n"
+      "incb   %[dst], all, mul #2                        \n"
+      "b.gt    1b                                        \n"
+
+      "2:                                                \n"
+      "adds     %w[width], %w[width], %w[vl], lsl #1     \n"
+      "b.eq     99f                                      \n"
+
+      // Calculate a pair of predicates for the final iteration to deal with
+      // the tail.
+      "whilelt p0.h, wzr, %w[width]                      \n"
+      "whilelt p1.h, %w[vl], %w[width]                   \n"
+      "ld1h   {z1.h}, p0/z, [%[src]]                     \n"
+      "ld1h   {z2.h}, p1/z, [%[src], #1, mul vl]         \n"
+      "umulh  z1.h, z1.h, z0.h                           \n"
+      "umulh  z2.h, z2.h, z0.h                           \n"
+      "st1h   {z1.h}, p0, [%[dst]]                       \n"
+      "st1h   {z2.h}, p1, [%[dst], #1, mul vl]           \n"
+
+      "99:                                               \n"
+      : [src] "+r"(src_y),    // %[src]
+        [dst] "+r"(dst_y),    // %[dst]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      : [scale] "r"(scale)    // %[scale]
+      : "cc", "memory", "z0", "z1", "z2", "p0", "p1");
+}
+
+#define HALFFLOAT_SVE                                    \
+  "scvtf       z0.s, p0/m, z0.s                      \n" \
+  "scvtf       z1.s, p0/m, z1.s                      \n" \
+  "scvtf       z2.s, p0/m, z2.s                      \n" \
+  "scvtf       z3.s, p0/m, z3.s                      \n" \
+  "fmul        z0.s, z0.s, z4.s                      \n" \
+  "fmul        z1.s, z1.s, z4.s                      \n" \
+  "fmul        z2.s, z2.s, z4.s                      \n" \
+  "fmul        z3.s, z3.s, z4.s                      \n" \
+  "uqshrnb     z0.h, z0.s, #13                       \n" \
+  "uqshrnb     z1.h, z1.s, #13                       \n" \
+  "uqshrnb     z2.h, z2.s, #13                       \n" \
+  "uqshrnb     z3.h, z3.s, #13                       \n"
+
+void HalfFloatRow_SVE2(const uint16_t* src,
+                       uint16_t* dst,
+                       float scale,
+                       int width) {
+  uint64_t vl;
+  asm("cntw %x0" : "=r"(vl));
+  asm volatile(
+      "mov         z4.s, %s[scale]                       \n"
+      "subs        %w[width], %w[width], %w[vl], lsl #2  \n"
+      "b.lt        2f                                    \n"
+
+      // Run bulk of computation with all-true predicates to avoid predicate
+      // generation overhead.
+      "ptrue       p0.s                                  \n"
+      "1:                                                \n"
+      "ld1h        {z0.s}, p0/z, [%[src]]                \n"
+      "ld1h        {z1.s}, p0/z, [%[src], #1, mul vl]    \n"
+      "ld1h        {z2.s}, p0/z, [%[src], #2, mul vl]    \n"
+      "ld1h        {z3.s}, p0/z, [%[src], #3, mul vl]    \n"
+      "incb        %[src], all, mul #2                   \n"  //
+      HALFFLOAT_SVE
+      "subs        %w[width], %w[width], %w[vl], lsl #2  \n"
+      "st1h        {z0.s}, p0, [%[dst]]                  \n"
+      "st1h        {z1.s}, p0, [%[dst], #1, mul vl]      \n"
+      "st1h        {z2.s}, p0, [%[dst], #2, mul vl]      \n"
+      "st1h        {z3.s}, p0, [%[dst], #3, mul vl]      \n"
+      "incb        %[dst], all, mul #2                   \n"
+      "b.ge        1b                                    \n"
+
+      "2:                                                \n"
+      "adds     %w[width], %w[width], %w[vl], lsl #2     \n"
+      "b.eq     99f                                      \n"
+
+      // Calculate predicates for the final iteration to deal with the tail.
+      "whilelt     p0.s, wzr, %w[width]                  \n"
+      "whilelt     p1.s, %w[vl], %w[width]               \n"
+      "whilelt     p2.s, %w[vl2], %w[width]              \n"
+      "whilelt     p3.s, %w[vl3], %w[width]              \n"
+      "ld1h        {z0.s}, p0/z, [%[src]]                \n"
+      "ld1h        {z1.s}, p1/z, [%[src], #1, mul vl]    \n"
+      "ld1h        {z2.s}, p2/z, [%[src], #2, mul vl]    \n"
+      "ld1h        {z3.s}, p3/z, [%[src], #3, mul vl]    \n"  //
+      HALFFLOAT_SVE
+      "st1h        {z0.s}, p0, [%[dst]]                  \n"
+      "st1h        {z1.s}, p1, [%[dst], #1, mul vl]      \n"
+      "st1h        {z2.s}, p2, [%[dst], #2, mul vl]      \n"
+      "st1h        {z3.s}, p3, [%[dst], #3, mul vl]      \n"
+
+      "99:                                               \n"
+      : [src] "+r"(src),                        // %[src]
+        [dst] "+r"(dst),                        // %[dst]
+        [width] "+r"(width)                     // %[width]
+      : [vl] "r"(vl),                           // %[vl]
+        [vl2] "r"(vl * 2),                      // %[vl2]
+        [vl3] "r"(vl * 3),                      // %[vl3]
+        [scale] "w"(scale * 1.9259299444e-34f)  // %[scale]
+      : "cc", "memory", "z0", "z1", "z2", "z3", "z4", "p0", "p1", "p2", "p3");
+}
+
+void HalfFloat1Row_SVE2(const uint16_t* src,
+                        uint16_t* dst,
+                        float scale,
+                        int width) {
+  uint64_t vl;
+  asm volatile(
+      "cnth        %x[vl]                                \n"
+      "subs        %w[width], %w[width], %w[vl], lsl #1  \n"
+      "b.lt        2f                                    \n"
+
+      // Run bulk of computation with all-true predicates to avoid predicate
+      // generation overhead.
+      "ptrue       p0.h                                  \n"
+      "1:                                                \n"
+      "ld1h        {z0.h}, p0/z, [%[src]]                \n"
+      "ld1h        {z1.h}, p0/z, [%[src], #1, mul vl]    \n"
+      "incb        %[src], all, mul #2                   \n"
+      "ucvtf       z0.h, p0/m, z0.h                      \n"
+      "ucvtf       z1.h, p0/m, z1.h                      \n"
+      "subs        %w[width], %w[width], %w[vl], lsl #1  \n"
+      "st1h        {z0.h}, p0, [%[dst]]                  \n"
+      "st1h        {z1.h}, p0, [%[dst], #1, mul vl]      \n"
+      "incb        %[dst], all, mul #2                   \n"
+      "b.ge        1b                                    \n"
+
+      "2:                                                \n"
+      "adds     %w[width], %w[width], %w[vl], lsl #1     \n"
+      "b.eq     99f                                      \n"
+
+      // Calculate predicates for the final iteration to deal with the tail.
+      "whilelt     p0.h, wzr, %w[width]                  \n"
+      "whilelt     p1.h, %w[vl], %w[width]               \n"
+      "ld1h        {z0.h}, p0/z, [%[src]]                \n"
+      "ld1h        {z1.h}, p1/z, [%[src], #1, mul vl]    \n"
+      "ucvtf       z0.h, p0/m, z0.h                      \n"
+      "ucvtf       z1.h, p0/m, z1.h                      \n"
+      "st1h        {z0.h}, p0, [%[dst]]                  \n"
+      "st1h        {z1.h}, p1, [%[dst], #1, mul vl]      \n"
+
+      "99:                                               \n"
+      : [src] "+r"(src),      // %[src]
+        [dst] "+r"(dst),      // %[dst]
+        [width] "+r"(width),  // %[width]
+        [vl] "=&r"(vl)        // %[vl]
+      :
+      : "cc", "memory", "z0", "z1", "p0", "p1");
+}
+
+void I210ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I210ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void I210AlphaToARGBRow_SVE2(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  I210AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+void I210ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I210ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+void P210ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  P210ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+void P210ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  P210ToAR30Row_SVE_SC(src_y, src_uv, dst_ar30, yuvconstants, width);
+}
+
+void I410ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I410ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void I410AlphaToARGBRow_SVE2(const uint16_t* src_y,
+                             const uint16_t* src_u,
+                             const uint16_t* src_v,
+                             const uint16_t* src_a,
+                             uint8_t* dst_argb,
+                             const struct YuvConstants* yuvconstants,
+                             int width) {
+  I410AlphaToARGBRow_SVE_SC(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
+                            width);
+}
+
+void I410ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I410ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+void P410ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  P410ToARGBRow_SVE_SC(src_y, src_uv, dst_argb, yuvconstants, width);
+}
+
+void P410ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_uv,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  P410ToAR30Row_SVE_SC(src_y, src_uv, dst_ar30, yuvconstants, width);
+}
+
+void I212ToAR30Row_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_ar30,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I212ToAR30Row_SVE_SC(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
+}
+
+void I212ToARGBRow_SVE2(const uint16_t* src_y,
+                        const uint16_t* src_u,
+                        const uint16_t* src_v,
+                        uint8_t* dst_argb,
+                        const struct YuvConstants* yuvconstants,
+                        int width) {
+  I212ToARGBRow_SVE_SC(src_y, src_u, src_v, dst_argb, yuvconstants, width);
+}
+
+void Convert8To8Row_SVE2(const uint8_t* src_y,
+                         uint8_t* dst_y,
+                         int scale,
+                         int bias,
+                         int width) {
+  Convert8To8Row_SVE_SC(src_y, dst_y, scale, bias, width);
+}
+
+#endif  // !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__)
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
diff --git a/source/row_win.cc b/source/row_win.cc
index 5fb2852..1a57ee4 100644
--- a/source/row_win.cc
+++ b/source/row_win.cc
@@ -12,7 +12,8 @@
 
 // This module is for Visual C 32/64 bit
 #if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && \
-    !defined(__clang__) && (defined(_M_IX86) || defined(_M_X64))
+    (defined(_M_IX86) || defined(_M_X64)) &&             \
+    (!defined(__clang__) || defined(LIBYUV_ENABLE_ROWWIN))
 
 #if defined(_M_ARM64EC)
 #include <intrin.h>
@@ -182,15 +183,52 @@
 
 // 32 bit
 #else  // defined(_M_X64)
-#ifdef HAS_ARGBTOYROW_SSSE3
 
-// Constants for ARGB.
-static const vec8 kARGBToY = {13, 65, 33, 0, 13, 65, 33, 0,
-                              13, 65, 33, 0, 13, 65, 33, 0};
+#ifdef HAS_ARGBTOUVROW_SSSE3
+
+// 8 bit fixed point 0.5, for bias of UV.
+static const ulvec8 kBiasUV128 = {
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
+
+// NV21 shuf 8 VU to 16 UV.
+static const lvec8 kShuffleNV21 = {
+    1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6,
+    1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6,
+};
+
+// YUY2 shuf 16 Y to 32 Y.
+static const lvec8 kShuffleYUY2Y = {0,  0,  2,  2,  4,  4,  6,  6,  8,  8, 10,
+                                    10, 12, 12, 14, 14, 0,  0,  2,  2,  4, 4,
+                                    6,  6,  8,  8,  10, 10, 12, 12, 14, 14};
+
+// YUY2 shuf 8 UV to 16 UV.
+static const lvec8 kShuffleYUY2UV = {1,  3,  1,  3,  5,  7,  5,  7,  9,  11, 9,
+                                     11, 13, 15, 13, 15, 1,  3,  1,  3,  5,  7,
+                                     5,  7,  9,  11, 9,  11, 13, 15, 13, 15};
+
+// UYVY shuf 16 Y to 32 Y.
+static const lvec8 kShuffleUYVYY = {1,  1,  3,  3,  5,  5,  7,  7,  9,  9, 11,
+                                    11, 13, 13, 15, 15, 1,  1,  3,  3,  5, 5,
+                                    7,  7,  9,  9,  11, 11, 13, 13, 15, 15};
+
+// UYVY shuf 8 UV to 16 UV.
+static const lvec8 kShuffleUYVYUV = {0,  2,  0,  2,  4,  6,  4,  6,  8,  10, 8,
+                                     10, 12, 14, 12, 14, 0,  2,  0,  2,  4,  6,
+                                     4,  6,  8,  10, 8,  10, 12, 14, 12, 14};
 
 // JPeg full range.
 static const vec8 kARGBToYJ = {15, 75, 38, 0, 15, 75, 38, 0,
                                15, 75, 38, 0, 15, 75, 38, 0};
+#endif
+
+// vpermd for vphaddw + vpackuswb vpermd.
+static const lvec32 kPermdARGBToY_AVX = {0, 4, 1, 5, 2, 6, 3, 7};
+
+// Constants for ARGB.
+static const vec8 kARGBToY = {13, 65, 33, 0, 13, 65, 33, 0,
+                              13, 65, 33, 0, 13, 65, 33, 0};
 
 static const vec8 kARGBToU = {112, -74, -38, 0, 112, -74, -38, 0,
                               112, -74, -38, 0, 112, -74, -38, 0};
@@ -246,12 +284,6 @@
 // 7 bit fixed point 0.5.
 static const vec16 kAddYJ64 = {64, 64, 64, 64, 64, 64, 64, 64};
 
-// 8 bit fixed point 0.5, for bias of UV.
-static const ulvec8 kBiasUV128 = {
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
-    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
-
 // Shuffle table for converting RGB24 to ARGB.
 static const uvec8 kShuffleMaskRGB24ToARGB = {
     0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u};
@@ -287,32 +319,6 @@
 static const uvec8 kShuffleMaskARGBToRGB24_0 = {
     0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u};
 
-// YUY2 shuf 16 Y to 32 Y.
-static const lvec8 kShuffleYUY2Y = {0,  0,  2,  2,  4,  4,  6,  6,  8,  8, 10,
-                                    10, 12, 12, 14, 14, 0,  0,  2,  2,  4, 4,
-                                    6,  6,  8,  8,  10, 10, 12, 12, 14, 14};
-
-// YUY2 shuf 8 UV to 16 UV.
-static const lvec8 kShuffleYUY2UV = {1,  3,  1,  3,  5,  7,  5,  7,  9,  11, 9,
-                                     11, 13, 15, 13, 15, 1,  3,  1,  3,  5,  7,
-                                     5,  7,  9,  11, 9,  11, 13, 15, 13, 15};
-
-// UYVY shuf 16 Y to 32 Y.
-static const lvec8 kShuffleUYVYY = {1,  1,  3,  3,  5,  5,  7,  7,  9,  9, 11,
-                                    11, 13, 13, 15, 15, 1,  1,  3,  3,  5, 5,
-                                    7,  7,  9,  9,  11, 11, 13, 13, 15, 15};
-
-// UYVY shuf 8 UV to 16 UV.
-static const lvec8 kShuffleUYVYUV = {0,  2,  0,  2,  4,  6,  4,  6,  8,  10, 8,
-                                     10, 12, 14, 12, 14, 0,  2,  0,  2,  4,  6,
-                                     4,  6,  8,  10, 8,  10, 12, 14, 12, 14};
-
-// NV21 shuf 8 VU to 16 UV.
-static const lvec8 kShuffleNV21 = {
-    1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6,
-    1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6,
-};
-
 // Duplicates gray value 3 times and fills in alpha opaque.
 __declspec(naked) void J400ToARGBRow_SSE2(const uint8_t* src_y,
                                           uint8_t* dst_argb,
@@ -1240,8 +1246,6 @@
 }
 
 #ifdef HAS_ARGBTOYROW_AVX2
-// vpermd for vphaddw + vpackuswb vpermd.
-static const lvec32 kPermdARGBToY_AVX = {0, 4, 1, 5, 2, 6, 3, 7};
 
 // Convert 32 ARGB pixels (128 bytes) to 32 Y values.
 __declspec(naked) void ARGBToYRow_AVX2(const uint8_t* src_argb,
@@ -1511,7 +1515,9 @@
     mov        edx, [esp + 8 + 12]  // dst_u
     mov        edi, [esp + 8 + 16]  // dst_v
     mov        ecx, [esp + 8 + 20]  // width
+    // TODO: change biasuv to 0x8000
     movdqa     xmm5, xmmword ptr kBiasUV128
+        // TODO: use negated coefficients to allow -128
     movdqa     xmm6, xmmword ptr kARGBToVJ
     movdqa     xmm7, xmmword ptr kARGBToUJ
     sub        edi, edx  // stride from u to v
@@ -1552,10 +1558,12 @@
     pmaddubsw  xmm3, xmm6
     phaddw     xmm0, xmm2
     phaddw     xmm1, xmm3
+        // TODO: negate by subtracting from 0x8000
     paddw      xmm0, xmm5  // +.5 rounding -> unsigned
     paddw      xmm1, xmm5
     psraw      xmm0, 8
     psraw      xmm1, 8
+    // TODO: packuswb
     packsswb   xmm0, xmm1
 
         // step 3 - store 8 U and 8 V values
@@ -1981,7 +1989,6 @@
     ret
   }
 }
-#endif  // HAS_ARGBTOYROW_SSSE3
 
 // Read 16 UV from 444
 #define READYUV444_AVX2 \
diff --git a/source/scale.cc b/source/scale.cc
index b7a602b..76379fd 100644
--- a/source/scale.cc
+++ b/source/scale.cc
@@ -74,6 +74,13 @@
     }
   }
 #endif
+#if defined(HAS_SCALEROWDOWN2_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleRowDown2 = filtering == kFilterNone     ? ScaleRowDown2_SME
+                    : filtering == kFilterLinear ? ScaleRowDown2Linear_SME
+                                                 : ScaleRowDown2Box_SME;
+  }
+#endif
 #if defined(HAS_SCALEROWDOWN2_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
     ScaleRowDown2 =
@@ -181,8 +188,16 @@
 
 #if defined(HAS_SCALEROWDOWN2_16_NEON)
   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 16)) {
-    ScaleRowDown2 =
-        filtering ? ScaleRowDown2Box_16_NEON : ScaleRowDown2_16_NEON;
+    ScaleRowDown2 = filtering == kFilterNone     ? ScaleRowDown2_16_NEON
+                    : filtering == kFilterLinear ? ScaleRowDown2Linear_16_NEON
+                                                 : ScaleRowDown2Box_16_NEON;
+  }
+#endif
+#if defined(HAS_SCALEROWDOWN2_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleRowDown2 = filtering == kFilterNone     ? ScaleRowDown2_16_SME
+                    : filtering == kFilterLinear ? ScaleRowDown2Linear_16_SME
+                                                 : ScaleRowDown2Box_16_SME;
   }
 #endif
 #if defined(HAS_SCALEROWDOWN2_16_SSE2)
@@ -279,7 +294,7 @@
   if (TestCpuFlag(kCpuHasNEON)) {
     ScaleRowDown4 =
         filtering ? ScaleRowDown4Box_Any_NEON : ScaleRowDown4_Any_NEON;
-    if (IS_ALIGNED(dst_width, 8)) {
+    if (IS_ALIGNED(dst_width, 16)) {
       ScaleRowDown4 = filtering ? ScaleRowDown4Box_NEON : ScaleRowDown4_NEON;
     }
   }
@@ -407,14 +422,11 @@
   }
 #if defined(HAS_SCALEROWDOWN34_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
-    if (!filtering) {
-      ScaleRowDown34_0 = ScaleRowDown34_Any_NEON;
-      ScaleRowDown34_1 = ScaleRowDown34_Any_NEON;
-    } else {
-      ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_NEON;
-      ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_NEON;
-    }
+#if defined(__aarch64__)
+    if (dst_width % 48 == 0) {
+#else
     if (dst_width % 24 == 0) {
+#endif
       if (!filtering) {
         ScaleRowDown34_0 = ScaleRowDown34_NEON;
         ScaleRowDown34_1 = ScaleRowDown34_NEON;
@@ -422,18 +434,19 @@
         ScaleRowDown34_0 = ScaleRowDown34_0_Box_NEON;
         ScaleRowDown34_1 = ScaleRowDown34_1_Box_NEON;
       }
+    } else {
+      if (!filtering) {
+        ScaleRowDown34_0 = ScaleRowDown34_Any_NEON;
+        ScaleRowDown34_1 = ScaleRowDown34_Any_NEON;
+      } else {
+        ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_NEON;
+        ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_NEON;
+      }
     }
   }
 #endif
 #if defined(HAS_SCALEROWDOWN34_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
-    if (!filtering) {
-      ScaleRowDown34_0 = ScaleRowDown34_Any_MSA;
-      ScaleRowDown34_1 = ScaleRowDown34_Any_MSA;
-    } else {
-      ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_MSA;
-      ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_MSA;
-    }
     if (dst_width % 48 == 0) {
       if (!filtering) {
         ScaleRowDown34_0 = ScaleRowDown34_MSA;
@@ -442,18 +455,19 @@
         ScaleRowDown34_0 = ScaleRowDown34_0_Box_MSA;
         ScaleRowDown34_1 = ScaleRowDown34_1_Box_MSA;
       }
+    } else {
+      if (!filtering) {
+        ScaleRowDown34_0 = ScaleRowDown34_Any_MSA;
+        ScaleRowDown34_1 = ScaleRowDown34_Any_MSA;
+      } else {
+        ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_MSA;
+        ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_MSA;
+      }
     }
   }
 #endif
 #if defined(HAS_SCALEROWDOWN34_LSX)
   if (TestCpuFlag(kCpuHasLSX)) {
-    if (!filtering) {
-      ScaleRowDown34_0 = ScaleRowDown34_Any_LSX;
-      ScaleRowDown34_1 = ScaleRowDown34_Any_LSX;
-    } else {
-      ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_LSX;
-      ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_LSX;
-    }
     if (dst_width % 48 == 0) {
       if (!filtering) {
         ScaleRowDown34_0 = ScaleRowDown34_LSX;
@@ -462,18 +476,19 @@
         ScaleRowDown34_0 = ScaleRowDown34_0_Box_LSX;
         ScaleRowDown34_1 = ScaleRowDown34_1_Box_LSX;
       }
+    } else {
+      if (!filtering) {
+        ScaleRowDown34_0 = ScaleRowDown34_Any_LSX;
+        ScaleRowDown34_1 = ScaleRowDown34_Any_LSX;
+      } else {
+        ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_LSX;
+        ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_LSX;
+      }
     }
   }
 #endif
 #if defined(HAS_SCALEROWDOWN34_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3)) {
-    if (!filtering) {
-      ScaleRowDown34_0 = ScaleRowDown34_Any_SSSE3;
-      ScaleRowDown34_1 = ScaleRowDown34_Any_SSSE3;
-    } else {
-      ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_SSSE3;
-      ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_SSSE3;
-    }
     if (dst_width % 24 == 0) {
       if (!filtering) {
         ScaleRowDown34_0 = ScaleRowDown34_SSSE3;
@@ -482,6 +497,14 @@
         ScaleRowDown34_0 = ScaleRowDown34_0_Box_SSSE3;
         ScaleRowDown34_1 = ScaleRowDown34_1_Box_SSSE3;
       }
+    } else {
+      if (!filtering) {
+        ScaleRowDown34_0 = ScaleRowDown34_Any_SSSE3;
+        ScaleRowDown34_1 = ScaleRowDown34_Any_SSSE3;
+      } else {
+        ScaleRowDown34_0 = ScaleRowDown34_0_Box_Any_SSSE3;
+        ScaleRowDown34_1 = ScaleRowDown34_1_Box_Any_SSSE3;
+      }
     }
   }
 #endif
@@ -1150,6 +1173,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -1289,6 +1317,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_16_SME;
+  }
+#endif
 
 #if defined(HAS_SCALEFILTERCOLS_16_SSSE3)
   if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
@@ -1370,6 +1403,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     InterpolateRow = InterpolateRow_RVV;
@@ -1870,6 +1908,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_16_SME;
+  }
+#endif
 
   if (filtering && src_width >= 32768) {
     ScaleFilterCols = ScaleFilterCols64_16_C;
@@ -2701,6 +2744,38 @@
   return r;
 }
 
+LIBYUV_API
+int NV24Scale(const uint8_t* src_y,
+              int src_stride_y,
+              const uint8_t* src_uv,
+              int src_stride_uv,
+              int src_width,
+              int src_height,
+              uint8_t* dst_y,
+              int dst_stride_y,
+              uint8_t* dst_uv,
+              int dst_stride_uv,
+              int dst_width,
+              int dst_height,
+              enum FilterMode filtering) {
+  int r;
+
+  if (!src_y || !src_uv || src_width <= 0 || src_height == 0 ||
+      src_width > 32768 || src_height > 32768 || !dst_y || !dst_uv ||
+      dst_width <= 0 || dst_height <= 0) {
+    return -1;
+  }
+
+  r = ScalePlane(src_y, src_stride_y, src_width, src_height, dst_y,
+                 dst_stride_y, dst_width, dst_height, filtering);
+  if (r != 0) {
+    return r;
+  }
+  r = UVScale(src_uv, src_stride_uv, src_width, src_height, dst_uv,
+              dst_stride_uv, dst_width, dst_height, filtering);
+  return r;
+}
+
 // Deprecated api
 LIBYUV_API
 int Scale(const uint8_t* src_y,
diff --git a/source/scale_any.cc b/source/scale_any.cc
index f657687..1433446 100644
--- a/source/scale_any.cc
+++ b/source/scale_any.cc
@@ -202,7 +202,7 @@
       15)
 #endif
 #ifdef HAS_SCALEROWDOWN4_NEON
-SDANY(ScaleRowDown4_Any_NEON, ScaleRowDown4_NEON, ScaleRowDown4_C, 4, 1, 7)
+SDANY(ScaleRowDown4_Any_NEON, ScaleRowDown4_NEON, ScaleRowDown4_C, 4, 1, 15)
 SDANY(ScaleRowDown4Box_Any_NEON,
       ScaleRowDown4Box_NEON,
       ScaleRowDown4Box_C,
@@ -249,6 +249,26 @@
       23)
 #endif
 #ifdef HAS_SCALEROWDOWN34_NEON
+#ifdef __aarch64__
+SDANY(ScaleRowDown34_Any_NEON,
+      ScaleRowDown34_NEON,
+      ScaleRowDown34_C,
+      4 / 3,
+      1,
+      47)
+SDANY(ScaleRowDown34_0_Box_Any_NEON,
+      ScaleRowDown34_0_Box_NEON,
+      ScaleRowDown34_0_Box_C,
+      4 / 3,
+      1,
+      47)
+SDANY(ScaleRowDown34_1_Box_Any_NEON,
+      ScaleRowDown34_1_Box_NEON,
+      ScaleRowDown34_1_Box_C,
+      4 / 3,
+      1,
+      47)
+#else
 SDANY(ScaleRowDown34_Any_NEON,
       ScaleRowDown34_NEON,
       ScaleRowDown34_C,
@@ -268,6 +288,7 @@
       1,
       23)
 #endif
+#endif
 #ifdef HAS_SCALEROWDOWN34_MSA
 SDANY(ScaleRowDown34_Any_MSA,
       ScaleRowDown34_MSA,
@@ -749,12 +770,20 @@
 #endif
 
 #ifdef HAS_SCALEROWUP2_LINEAR_NEON
+#ifdef __aarch64__
+SUH2LANY(ScaleRowUp2_Linear_Any_NEON,
+         ScaleRowUp2_Linear_NEON,
+         ScaleRowUp2_Linear_C,
+         31,
+         uint8_t)
+#else
 SUH2LANY(ScaleRowUp2_Linear_Any_NEON,
          ScaleRowUp2_Linear_NEON,
          ScaleRowUp2_Linear_C,
          15,
          uint8_t)
 #endif
+#endif
 
 #ifdef HAS_SCALEROWUP2_LINEAR_12_NEON
 SUH2LANY(ScaleRowUp2_Linear_12_Any_NEON,
diff --git a/source/scale_argb.cc b/source/scale_argb.cc
index 18bdeb8..5fa58fd 100644
--- a/source/scale_argb.cc
+++ b/source/scale_argb.cc
@@ -11,6 +11,9 @@
 #include "libyuv/scale.h"
 
 #include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "libyuv/cpu_id.h"
@@ -96,6 +99,14 @@
     }
   }
 #endif
+#if defined(HAS_SCALEARGBROWDOWN2_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_SME
+                        : filtering == kFilterLinear
+                            ? ScaleARGBRowDown2Linear_SME
+                            : ScaleARGBRowDown2Box_SME;
+  }
+#endif
 #if defined(HAS_SCALEARGBROWDOWN2_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     ScaleARGBRowDown2 =
@@ -128,7 +139,9 @@
     }
   }
 #endif
-#if defined(HAS_SCALEARGBROWDOWN2_RVV)
+#if defined(HAS_SCALEARGBROWDOWN2_RVV) &&       \
+    defined(HAS_SCALEARGBROWDOWN2LINEAR_RVV) && \
+    defined(HAS_SCALEARGBROWDOWN2BOX_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     ScaleARGBRowDown2 =
         filtering == kFilterNone
@@ -199,7 +212,12 @@
     }
   }
 #endif
-#if defined(HAS_SCALEARGBROWDOWN2_RVV)
+#if defined(HAS_SCALEARGBROWDOWN2_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleARGBRowDown2 = ScaleARGBRowDown2Box_SME;
+  }
+#endif
+#if defined(HAS_SCALEARGBROWDOWN2BOX_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     ScaleARGBRowDown2 = ScaleARGBRowDown2Box_RVV;
   }
@@ -363,6 +381,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -413,6 +436,12 @@
     }
   }
 #endif
+#if defined(HAS_SCALEARGBFILTERCOLS_RVV)
+  if (TestCpuFlag(kCpuHasRVV)) {
+    ScaleARGBFilterCols = ScaleARGBFilterCols_RVV;
+  }
+#endif
+
   // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
   // Allocate a row of ARGB.
   {
@@ -491,6 +520,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -545,6 +579,11 @@
     }
   }
 #endif
+#if defined(HAS_SCALEARGBFILTERCOLS_RVV)
+  if (filtering && TestCpuFlag(kCpuHasRVV)) {
+    ScaleARGBFilterCols = ScaleARGBFilterCols_RVV;
+  }
+#endif
 #if defined(HAS_SCALEARGBCOLS_SSE2)
   if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
     ScaleARGBFilterCols = ScaleARGBCols_SSE2;
@@ -698,6 +737,16 @@
     }
   }
 #endif
+#if defined(HAS_I422TOARGBROW_SVE2)
+  if (TestCpuFlag(kCpuHasSVE2)) {
+    I422ToARGBRow = I422ToARGBRow_SVE2;
+  }
+#endif
+#if defined(HAS_I422TOARGBROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    I422ToARGBRow = I422ToARGBRow_SME;
+  }
+#endif
 #if defined(HAS_I422TOARGBROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     I422ToARGBRow = I422ToARGBRow_Any_MSA;
@@ -755,6 +804,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -813,6 +867,11 @@
     }
   }
 #endif
+#if defined(HAS_SCALEARGBFILTERCOLS_RVV)
+  if (filtering && TestCpuFlag(kCpuHasRVV)) {
+    ScaleARGBFilterCols = ScaleARGBFilterCols_RVV;
+  }
+#endif
 #if defined(HAS_SCALEARGBCOLS_SSE2)
   if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
     ScaleARGBFilterCols = ScaleARGBCols_SSE2;
@@ -1054,14 +1113,14 @@
     } else {
       // Optimized even scale down. ie 2, 4, 6, 8, 10x.
       if (!(dx & 0x10000) && !(dy & 0x10000)) {
-        if (dx == 0x20000) {
+        if (dx == 0x20000 && dy == 0x20000) {
           // Optimized 1/2 downsample.
           ScaleARGBDown2(src_width, src_height, clip_width, clip_height,
                          src_stride, dst_stride, src, dst, x, dx, y, dy,
                          filtering);
           return 0;
         }
-        if (dx == 0x40000 && filtering == kFilterBox) {
+        if (dx == 0x40000 && dy == 0x40000 && filtering == kFilterBox) {
           // Optimized 1/4 box downsample.
           return ScaleARGBDown4Box(src_width, src_height, clip_width,
                                    clip_height, src_stride, dst_stride, src,
@@ -1173,18 +1232,28 @@
                        int clip_height,
                        enum FilterMode filtering) {
   int r;
-  uint8_t* argb_buffer = (uint8_t*)malloc(src_width * src_height * 4);
+  (void)src_fourcc;  // TODO(fbarchard): implement and/or assert.
+  (void)dst_fourcc;
+  const int abs_src_height = (src_height < 0) ? -src_height : src_height;
+  if (!src_y || !src_u || !src_v || !dst_argb || src_width <= 0 ||
+      src_width > INT_MAX / 4 || src_height == 0 || dst_width <= 0 ||
+      dst_height <= 0 || clip_width <= 0 || clip_height <= 0) {
+    return -1;
+  }
+  const uint64_t argb_buffer_size = (uint64_t)src_width * abs_src_height * 4;
+  if (argb_buffer_size > SIZE_MAX) {
+    return -1;  // Invalid size.
+  }
+  uint8_t* argb_buffer = (uint8_t*)malloc((size_t)argb_buffer_size);
   if (!argb_buffer) {
     return 1;  // Out of memory runtime error.
   }
-  (void)src_fourcc;  // TODO(fbarchard): implement and/or assert.
-  (void)dst_fourcc;
   I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
              argb_buffer, src_width * 4, src_width, src_height);
 
-  r = ARGBScaleClip(argb_buffer, src_width * 4, src_width, src_height, dst_argb,
-                    dst_stride_argb, dst_width, dst_height, clip_x, clip_y,
-                    clip_width, clip_height, filtering);
+  r = ARGBScaleClip(argb_buffer, src_width * 4, src_width, abs_src_height,
+                    dst_argb, dst_stride_argb, dst_width, dst_height, clip_x,
+                    clip_y, clip_width, clip_height, filtering);
   free(argb_buffer);
   return r;
 }
diff --git a/source/scale_common.cc b/source/scale_common.cc
index d07a39a..430afc2 100644
--- a/source/scale_common.cc
+++ b/source/scale_common.cc
@@ -1662,6 +1662,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -1755,6 +1760,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_16_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_16_SME;
+  }
+#endif
   for (j = 0; j < dst_height; ++j) {
     int yi;
     int yf;
@@ -1811,6 +1821,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_16TO8_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow_16To8 = InterpolateRow_16To8_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_16TO8_AVX2)
   if (TestCpuFlag(kCpuHasAVX2)) {
     InterpolateRow_16To8 = InterpolateRow_16To8_Any_AVX2;
diff --git a/source/scale_gcc.cc b/source/scale_gcc.cc
index 17eeffa..92f9e70 100644
--- a/source/scale_gcc.cc
+++ b/source/scale_gcc.cc
@@ -17,7 +17,9 @@
 #endif
 
 // This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
+#if !defined(LIBYUV_DISABLE_X86) &&               \
+    (defined(__x86_64__) || defined(__i386__)) && \
+    !defined(LIBYUV_ENABLE_ROWWIN)
 
 // Offsets for source bytes 0 to 9
 static const uvec8 kShuf0 = {0,   1,   3,   4,   5,   7,   8,   9,
@@ -100,7 +102,7 @@
   asm volatile(
       // 16 pixel loop.
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -114,8 +116,8 @@
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
-        ::"memory",
-        "cc", "xmm0", "xmm1");
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 void ScaleRowDown2Linear_SSSE3(const uint8_t* src_ptr,
@@ -124,13 +126,13 @@
                                int dst_width) {
   (void)src_stride;
   asm volatile(
-      "pcmpeqb     %%xmm4,%%xmm4                 \n"
-      "psrlw       $0xf,%%xmm4                   \n"
-      "packuswb    %%xmm4,%%xmm4                 \n"
+      "pcmpeqb     %%xmm4,%%xmm4                 \n"  // 0x0101
+      "pabsb       %%xmm4,%%xmm4                 \n"
+
       "pxor        %%xmm5,%%xmm5                 \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -146,8 +148,8 @@
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm4", "xmm5");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5");
 }
 
 void ScaleRowDown2Box_SSSE3(const uint8_t* src_ptr,
@@ -155,13 +157,12 @@
                             uint8_t* dst_ptr,
                             int dst_width) {
   asm volatile(
-      "pcmpeqb     %%xmm4,%%xmm4                 \n"
-      "psrlw       $0xf,%%xmm4                   \n"
-      "packuswb    %%xmm4,%%xmm4                 \n"
+      "pcmpeqb     %%xmm4,%%xmm4                 \n"  // 0x0101
+      "pabsb       %%xmm4,%%xmm4                 \n"
       "pxor        %%xmm5,%%xmm5                 \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%3,1),%%xmm2          \n"
@@ -195,8 +196,8 @@
                         uint8_t* dst_ptr,
                         int dst_width) {
   (void)src_stride;
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -208,12 +209,12 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
-               : "+r"(src_ptr),   // %0
-                 "+r"(dst_ptr),   // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1");
+      "vzeroupper  \n"
+      : "+r"(src_ptr),   // %0
+        "+r"(dst_ptr),   // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 void ScaleRowDown2Linear_AVX2(const uint8_t* src_ptr,
@@ -223,12 +224,11 @@
   (void)src_stride;
   asm volatile(
       "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"
-      "vpsrlw      $0xf,%%ymm4,%%ymm4            \n"
-      "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpabsb      %%ymm4,%%ymm4                 \n"
       "vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -242,12 +242,12 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm4", "xmm5");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5");
 }
 
 void ScaleRowDown2Box_AVX2(const uint8_t* src_ptr,
@@ -256,12 +256,11 @@
                            int dst_width) {
   asm volatile(
       "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"
-      "vpsrlw      $0xf,%%ymm4,%%ymm4            \n"
-      "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpabsb      %%ymm4,%%ymm4                 \n"
       "vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vmovdqu     0x00(%0,%3,1),%%ymm2          \n"
@@ -283,7 +282,7 @@
       "lea         0x20(%1),%1                   \n"
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),               // %0
         "+r"(dst_ptr),               // %1
         "+r"(dst_width)              // %2
@@ -303,7 +302,7 @@
       "pslld       $0x10,%%xmm5                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -319,8 +318,8 @@
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm5");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 
 void ScaleRowDown4Box_SSSE3(const uint8_t* src_ptr,
@@ -330,14 +329,13 @@
   intptr_t stridex3;
   asm volatile(
       "pcmpeqb     %%xmm4,%%xmm4                 \n"
-      "psrlw       $0xf,%%xmm4                   \n"
-      "movdqa      %%xmm4,%%xmm5                 \n"
-      "packuswb    %%xmm4,%%xmm4                 \n"
-      "psllw       $0x3,%%xmm5                   \n"
+      "pabsw       %%xmm4,%%xmm5                 \n"
+      "pabsb       %%xmm4,%%xmm4                 \n"  // 0x0101
+      "psllw       $0x3,%%xmm5                   \n"  // 0x0008
       "lea         0x00(%4,%4,2),%3              \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%4,1),%%xmm2          \n"
@@ -389,7 +387,7 @@
       "vpslld      $0x10,%%ymm5,%%ymm5           \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "lea         0x40(%0),%0                   \n"
@@ -404,12 +402,12 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm5");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm5");
 }
 
 void ScaleRowDown4Box_AVX2(const uint8_t* src_ptr,
@@ -418,12 +416,12 @@
                            int dst_width) {
   asm volatile(
       "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"
-      "vpsrlw      $0xf,%%ymm4,%%ymm4            \n"
-      "vpsllw      $0x3,%%ymm4,%%ymm5            \n"
-      "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpabsw      %%ymm4,%%ymm5                 \n"
+      "vpabsb      %%ymm4,%%ymm4                 \n"  // 0x0101
+      "vpsllw      $0x3,%%ymm5,%%ymm5            \n"  // 0x0008
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"
       "vmovdqu     0x20(%0),%%ymm1               \n"
       "vmovdqu     0x00(%0,%3,1),%%ymm2          \n"
@@ -457,7 +455,7 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                   // %0
         "+r"(dst_ptr),                   // %1
         "+r"(dst_width)                  // %2
@@ -481,8 +479,8 @@
         "m"(kShuf1),  // %1
         "m"(kShuf2)   // %2
   );
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm2               \n"
       "lea         0x20(%0),%0                   \n"
@@ -497,11 +495,11 @@
       "lea         0x18(%1),%1                   \n"
       "sub         $0x18,%2                      \n"
       "jg          1b                            \n"
-               : "+r"(src_ptr),   // %0
-                 "+r"(dst_ptr),   // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
+      : "+r"(src_ptr),   // %0
+        "+r"(dst_ptr),   // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
 }
 
 void ScaleRowDown34_1_Box_SSSE3(const uint8_t* src_ptr,
@@ -526,8 +524,8 @@
         "m"(kMadd11),  // %1
         "m"(kRound34)  // %2
   );
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm6                   \n"
       "movdqu      0x00(%0,%3,1),%%xmm7          \n"
       "pavgb       %%xmm7,%%xmm6                 \n"
@@ -559,13 +557,13 @@
       "lea         0x18(%1),%1                   \n"
       "sub         $0x18,%2                      \n"
       "jg          1b                            \n"
-               : "+r"(src_ptr),                // %0
-                 "+r"(dst_ptr),                // %1
-                 "+r"(dst_width)               // %2
-               : "r"((intptr_t)(src_stride)),  // %3
-                 "m"(kMadd21)                  // %4
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
-                 "xmm6", "xmm7");
+      : "+r"(src_ptr),                // %0
+        "+r"(dst_ptr),                // %1
+        "+r"(dst_width)               // %2
+      : "r"((intptr_t)(src_stride)),  // %3
+        "m"(kMadd21)                  // %4
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 
 void ScaleRowDown34_0_Box_SSSE3(const uint8_t* src_ptr,
@@ -591,8 +589,8 @@
         "m"(kRound34)  // %2
   );
 
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm6                   \n"
       "movdqu      0x00(%0,%3,1),%%xmm7          \n"
       "pavgb       %%xmm6,%%xmm7                 \n"
@@ -627,13 +625,13 @@
       "lea         0x18(%1),%1                   \n"
       "sub         $0x18,%2                      \n"
       "jg          1b                            \n"
-               : "+r"(src_ptr),                // %0
-                 "+r"(dst_ptr),                // %1
-                 "+r"(dst_width)               // %2
-               : "r"((intptr_t)(src_stride)),  // %3
-                 "m"(kMadd21)                  // %4
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
-                 "xmm6", "xmm7");
+      : "+r"(src_ptr),                // %0
+        "+r"(dst_ptr),                // %1
+        "+r"(dst_width)               // %2
+      : "r"((intptr_t)(src_stride)),  // %3
+        "m"(kMadd21)                  // %4
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 
 void ScaleRowDown38_SSSE3(const uint8_t* src_ptr,
@@ -646,7 +644,7 @@
       "movdqa      %4,%%xmm5                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -682,8 +680,8 @@
         "m"(kShufAb2),  // %2
         "m"(kScaleAb2)  // %3
   );
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%3,1),%%xmm1          \n"
       "lea         0x10(%0),%0                   \n"
@@ -703,12 +701,11 @@
       "lea         0x6(%1),%1                    \n"
       "sub         $0x6,%2                       \n"
       "jg          1b                            \n"
-               : "+r"(src_ptr),               // %0
-                 "+r"(dst_ptr),               // %1
-                 "+r"(dst_width)              // %2
-               : "r"((intptr_t)(src_stride))  // %3
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
-                 "xmm6");
+      : "+r"(src_ptr),               // %0
+        "+r"(dst_ptr),               // %1
+        "+r"(dst_width)              // %2
+      : "r"((intptr_t)(src_stride))  // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6");
 }
 
 void ScaleRowDown38_3_Box_SSSE3(const uint8_t* src_ptr,
@@ -725,8 +722,8 @@
         "m"(kShufAc3),   // %1
         "m"(kScaleAc33)  // %2
   );
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x00(%0,%3,1),%%xmm6          \n"
       "movhlps     %%xmm0,%%xmm1                 \n"
@@ -765,12 +762,12 @@
       "lea         0x6(%1),%1                    \n"
       "sub         $0x6,%2                       \n"
       "jg          1b                            \n"
-               : "+r"(src_ptr),               // %0
-                 "+r"(dst_ptr),               // %1
-                 "+r"(dst_width)              // %2
-               : "r"((intptr_t)(src_stride))  // %3
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
-                 "xmm6", "xmm7");
+      : "+r"(src_ptr),               // %0
+        "+r"(dst_ptr),               // %1
+        "+r"(dst_width)              // %2
+      : "r"((intptr_t)(src_stride))  // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6",
+        "xmm7");
 }
 
 static const uvec8 kLinearShuffleFar = {2,  3,  0, 1, 6,  7,  4,  5,
@@ -790,7 +787,7 @@
       "psllw       $1,%%xmm6                     \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm1                   \n"  // 01234567
       "movq        1(%0),%%xmm2                  \n"  // 12345678
       "movdqa      %%xmm1,%%xmm3                 \n"
@@ -840,8 +837,7 @@
                                ptrdiff_t dst_stride,
                                int dst_width) {
   asm volatile(
-      LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "pxor        %%xmm0,%%xmm0                 \n"  // 0
       // above line
       "movq        (%0),%%xmm1                   \n"  // 01234567
@@ -960,7 +956,7 @@
       "psllw       $1,%%xmm4                     \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // 01234567 (16)
       "movdqu      2(%0),%%xmm1                  \n"  // 12345678 (16)
 
@@ -1012,7 +1008,7 @@
       "movdqa      %5,%%xmm6                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       // above line
       "movdqu      (%0),%%xmm0                   \n"  // 01234567 (16)
       "movdqu      2(%0),%%xmm1                  \n"  // 12345678 (16)
@@ -1110,7 +1106,7 @@
       "pslld       $1,%%xmm4                     \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 0123 (16b)
       "movq        2(%0),%%xmm1                  \n"  // 1234 (16b)
 
@@ -1163,7 +1159,7 @@
       "pslld       $3,%%xmm6                     \n"  // all 8
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 0011 (16b, 1u1v)
       "movq        4(%0),%%xmm1                  \n"  // 1122 (16b, 1u1v)
       "punpcklwd   %%xmm7,%%xmm0                 \n"  // 0011 (near) (32b, 1u1v)
@@ -1271,7 +1267,7 @@
       "movdqa      %3,%%xmm3                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 01234567
       "movq        1(%0),%%xmm1                  \n"  // 12345678
       "punpcklwd   %%xmm0,%%xmm0                 \n"  // 0101232345456767
@@ -1312,7 +1308,7 @@
       "movdqa      %5,%%xmm7                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 01234567
       "movq        1(%0),%%xmm1                  \n"  // 12345678
       "punpcklwd   %%xmm0,%%xmm0                 \n"  // 0101232345456767
@@ -1397,7 +1393,7 @@
       "vbroadcastf128 %3,%%ymm3                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"  // 0123456789ABCDEF
       "vmovdqu     1(%0),%%xmm1                  \n"  // 123456789ABCDEF0
       "vpermq      $0b11011000,%%ymm0,%%ymm0     \n"
@@ -1419,7 +1415,7 @@
       "lea         0x20(%1),%1                   \n"  // 16 sample to 32 sample
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),      // %0
         "+r"(dst_ptr),      // %1
         "+r"(dst_width)     // %2
@@ -1441,7 +1437,7 @@
       "vbroadcastf128 %5,%%ymm7                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"  // 0123456789ABCDEF
       "vmovdqu     1(%0),%%xmm1                  \n"  // 123456789ABCDEF0
       "vpermq      $0b11011000,%%ymm0,%%ymm0     \n"
@@ -1500,7 +1496,7 @@
       "lea         0x20(%1),%1                   \n"  // 16 sample to 32 sample
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
@@ -1523,7 +1519,7 @@
       "vpsllw      $1,%%ymm4,%%ymm4              \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // 0123456789ABCDEF (16b)
       "vmovdqu     2(%0),%%ymm1                  \n"  // 123456789ABCDEF0 (16b)
 
@@ -1553,7 +1549,7 @@
       "lea         0x40(%1),%1                   \n"  // 16 sample to 32 sample
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),          // %0
         "+r"(dst_ptr),          // %1
         "+r"(dst_width)         // %2
@@ -1575,7 +1571,7 @@
       "vpsllw      $3,%%ymm4,%%ymm4              \n"  // all 8
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0),%%xmm0                   \n"  // 01234567 (16b)
       "vmovdqu     2(%0),%%xmm1                  \n"  // 12345678 (16b)
@@ -1615,7 +1611,7 @@
       "lea         0x20(%1),%1                   \n"  // 8 sample to 16 sample
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
@@ -1636,7 +1632,7 @@
       "vpslld      $1,%%ymm4,%%ymm4              \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"  // 01234567 (16b, 1u1v)
       "vmovdqu     2(%0),%%xmm1                  \n"  // 12345678 (16b, 1u1v)
 
@@ -1665,7 +1661,7 @@
       "lea         0x20(%1),%1                   \n"  // 8 pixel to 16 pixel
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
@@ -1686,7 +1682,7 @@
       "vpslld      $3,%%ymm6,%%ymm6              \n"  // all 8
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0),%%xmm0                   \n"  // 01234567 (16b, 1u1v)
       "vmovdqu     2(%0),%%xmm1                  \n"  // 12345678 (16b, 1u1v)
@@ -1749,7 +1745,7 @@
       "lea         0x20(%1),%1                   \n"  // 8 pixel to 16 pixel
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
@@ -1763,25 +1759,25 @@
 void ScaleAddRow_SSE2(const uint8_t* src_ptr,
                       uint16_t* dst_ptr,
                       int src_width) {
-      asm volatile("pxor        %%xmm5,%%xmm5                 \n"
+  asm volatile("pxor        %%xmm5,%%xmm5                 \n"
 
                // 16 pixel loop.
                LABELALIGN
-      "1:                                        \n"
-      "movdqu      (%0),%%xmm3                   \n"
-      "lea         0x10(%0),%0                   \n"  // src_ptr += 16
-      "movdqu      (%1),%%xmm0                   \n"
-      "movdqu      0x10(%1),%%xmm1               \n"
-      "movdqa      %%xmm3,%%xmm2                 \n"
-      "punpcklbw   %%xmm5,%%xmm2                 \n"
-      "punpckhbw   %%xmm5,%%xmm3                 \n"
-      "paddusw     %%xmm2,%%xmm0                 \n"
-      "paddusw     %%xmm3,%%xmm1                 \n"
-      "movdqu      %%xmm0,(%1)                   \n"
-      "movdqu      %%xmm1,0x10(%1)               \n"
-      "lea         0x20(%1),%1                   \n"
-      "sub         $0x10,%2                      \n"
-      "jg          1b                            \n"
+               "1:          \n"
+               "movdqu      (%0),%%xmm3                   \n"
+               "lea         0x10(%0),%0                   \n"  // src_ptr += 16
+               "movdqu      (%1),%%xmm0                   \n"
+               "movdqu      0x10(%1),%%xmm1               \n"
+               "movdqa      %%xmm3,%%xmm2                 \n"
+               "punpcklbw   %%xmm5,%%xmm2                 \n"
+               "punpckhbw   %%xmm5,%%xmm3                 \n"
+               "paddusw     %%xmm2,%%xmm0                 \n"
+               "paddusw     %%xmm3,%%xmm1                 \n"
+               "movdqu      %%xmm0,(%1)                   \n"
+               "movdqu      %%xmm1,0x10(%1)               \n"
+               "lea         0x20(%1),%1                   \n"
+               "sub         $0x10,%2                      \n"
+               "jg          1b                            \n"
                : "+r"(src_ptr),   // %0
                  "+r"(dst_ptr),   // %1
                  "+r"(src_width)  // %2
@@ -1794,23 +1790,23 @@
 void ScaleAddRow_AVX2(const uint8_t* src_ptr,
                       uint16_t* dst_ptr,
                       int src_width) {
-      asm volatile("vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
+  asm volatile("vpxor       %%ymm5,%%ymm5,%%ymm5          \n"
 
                LABELALIGN
-      "1:                                        \n"
-      "vmovdqu     (%0),%%ymm3                   \n"
-      "lea         0x20(%0),%0                   \n"  // src_ptr += 32
-      "vpermq      $0xd8,%%ymm3,%%ymm3           \n"
-      "vpunpcklbw  %%ymm5,%%ymm3,%%ymm2          \n"
-      "vpunpckhbw  %%ymm5,%%ymm3,%%ymm3          \n"
-      "vpaddusw    (%1),%%ymm2,%%ymm0            \n"
-      "vpaddusw    0x20(%1),%%ymm3,%%ymm1        \n"
-      "vmovdqu     %%ymm0,(%1)                   \n"
-      "vmovdqu     %%ymm1,0x20(%1)               \n"
-      "lea         0x40(%1),%1                   \n"
-      "sub         $0x20,%2                      \n"
-      "jg          1b                            \n"
-      "vzeroupper                                \n"
+               "1:          \n"
+               "vmovdqu     (%0),%%ymm3                   \n"
+               "lea         0x20(%0),%0                   \n"  // src_ptr += 32
+               "vpermq      $0xd8,%%ymm3,%%ymm3           \n"
+               "vpunpcklbw  %%ymm5,%%ymm3,%%ymm2          \n"
+               "vpunpckhbw  %%ymm5,%%ymm3,%%ymm3          \n"
+               "vpaddusw    (%1),%%ymm2,%%ymm0            \n"
+               "vpaddusw    0x20(%1),%%ymm3,%%ymm1        \n"
+               "vmovdqu     %%ymm0,(%1)                   \n"
+               "vmovdqu     %%ymm1,0x20(%1)               \n"
+               "lea         0x40(%1),%1                   \n"
+               "sub         $0x20,%2                      \n"
+               "jg          1b                            \n"
+               "vzeroupper  \n"
                : "+r"(src_ptr),   // %0
                  "+r"(dst_ptr),   // %1
                  "+r"(src_width)  // %2
@@ -1856,7 +1852,7 @@
       "pextrw      $0x3,%%xmm2,%k4               \n"
 
       LABELALIGN
-      "2:                                        \n"
+      "2:          \n"
       "movdqa      %%xmm2,%%xmm1                 \n"
       "paddd       %%xmm3,%%xmm2                 \n"
       "movzwl      0x00(%1,%3,1),%k2             \n"
@@ -1883,7 +1879,7 @@
       "jge         2b                            \n"
 
       LABELALIGN
-      "29:                                       \n"
+      "29:         \n"
       "addl        $0x1,%5                       \n"
       "jl          99f                           \n"
       "movzwl      0x00(%1,%3,1),%k2             \n"
@@ -1899,7 +1895,7 @@
       "packuswb    %%xmm2,%%xmm2                 \n"
       "movd        %%xmm2,%k2                    \n"
       "mov         %b2,(%0)                      \n"
-      "99:                                       \n"
+      "99:         \n"
       : "+r"(dst_ptr),      // %0
         "+r"(src_ptr),      // %1
         "=&a"(temp_pixel),  // %2
@@ -1932,8 +1928,8 @@
                        int dx) {
   (void)x;
   (void)dx;
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%1),%%xmm0                   \n"
       "lea         0x10(%1),%1                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
@@ -1945,11 +1941,11 @@
       "sub         $0x20,%2                      \n"
       "jg          1b                            \n"
 
-               : "+r"(dst_ptr),   // %0
-                 "+r"(src_ptr),   // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1");
+      : "+r"(dst_ptr),   // %0
+        "+r"(src_ptr),   // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 void ScaleARGBRowDown2_SSE2(const uint8_t* src_argb,
@@ -1957,8 +1953,8 @@
                             uint8_t* dst_argb,
                             int dst_width) {
   (void)src_stride;
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -1967,11 +1963,11 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x4,%2                       \n"
       "jg          1b                            \n"
-               : "+r"(src_argb),  // %0
-                 "+r"(dst_argb),  // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1");
+      : "+r"(src_argb),  // %0
+        "+r"(dst_argb),  // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 void ScaleARGBRowDown2Linear_SSE2(const uint8_t* src_argb,
@@ -1979,8 +1975,8 @@
                                   uint8_t* dst_argb,
                                   int dst_width) {
   (void)src_stride;
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "lea         0x20(%0),%0                   \n"
@@ -1992,19 +1988,19 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x4,%2                       \n"
       "jg          1b                            \n"
-               : "+r"(src_argb),  // %0
-                 "+r"(dst_argb),  // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1");
+      : "+r"(src_argb),  // %0
+        "+r"(dst_argb),  // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 void ScaleARGBRowDown2Box_SSE2(const uint8_t* src_argb,
                                ptrdiff_t src_stride,
                                uint8_t* dst_argb,
                                int dst_width) {
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"
       "movdqu      0x10(%0),%%xmm1               \n"
       "movdqu      0x00(%0,%3,1),%%xmm2          \n"
@@ -2020,11 +2016,11 @@
       "lea         0x10(%1),%1                   \n"
       "sub         $0x4,%2                       \n"
       "jg          1b                            \n"
-               : "+r"(src_argb),              // %0
-                 "+r"(dst_argb),              // %1
-                 "+r"(dst_width)              // %2
-               : "r"((intptr_t)(src_stride))  // %3
-               : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
+      : "+r"(src_argb),              // %0
+        "+r"(dst_argb),              // %1
+        "+r"(dst_width)              // %2
+      : "r"((intptr_t)(src_stride))  // %3
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
 }
 
 // Reads 4 pixels at a time.
@@ -2042,7 +2038,7 @@
       "lea         0x00(%1,%1,2),%4              \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movd        (%0),%%xmm0                   \n"
       "movd        0x00(%0,%1,1),%%xmm1          \n"
       "punpckldq   %%xmm1,%%xmm0                 \n"
@@ -2060,8 +2056,8 @@
         "+r"(dst_argb),       // %2
         "+r"(dst_width),      // %3
         "=&r"(src_stepx_x12)  // %4
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm2", "xmm3");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
 }
 
 // Blends four 2x2 to 4x1.
@@ -2080,7 +2076,7 @@
       "lea         0x00(%0,%5,1),%5              \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"
       "movhps      0x00(%0,%1,1),%%xmm0          \n"
       "movq        0x00(%0,%1,2),%%xmm1          \n"
@@ -2107,8 +2103,8 @@
         "+rm"(dst_width),      // %3
         "=&r"(src_stepx_x12),  // %4
         "+r"(row1)             // %5
-        ::"memory",
-        "cc", "xmm0", "xmm1", "xmm2", "xmm3");
+      :
+      : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3");
 }
 
 void ScaleARGBCols_SSE2(uint8_t* dst_argb,
@@ -2136,7 +2132,7 @@
       "jl          49f                           \n"
 
       LABELALIGN
-      "40:                                       \n"
+      "40:         \n"
       "movd        0x00(%3,%0,4),%%xmm0          \n"
       "movd        0x00(%3,%1,4),%%xmm1          \n"
       "pextrw      $0x5,%%xmm2,%k0               \n"
@@ -2154,7 +2150,7 @@
       "sub         $0x4,%4                       \n"
       "jge         40b                           \n"
 
-      "49:                                       \n"
+      "49:         \n"
       "test        $0x2,%4                       \n"
       "je          29f                           \n"
       "movd        0x00(%3,%0,4),%%xmm0          \n"
@@ -2163,12 +2159,12 @@
       "punpckldq   %%xmm1,%%xmm0                 \n"
       "movq        %%xmm0,(%2)                   \n"
       "lea         0x8(%2),%2                    \n"
-      "29:                                       \n"
+      "29:         \n"
       "test        $0x1,%4                       \n"
       "je          99f                           \n"
       "movd        0x00(%3,%0,4),%%xmm0          \n"
       "movd        %%xmm0,(%2)                   \n"
-      "99:                                       \n"
+      "99:         \n"
       : "=&a"(x0),       // %0
         "=&d"(x1),       // %1
         "+r"(dst_argb),  // %2
@@ -2188,8 +2184,8 @@
                            int dx) {
   (void)x;
   (void)dx;
-  asm volatile(LABELALIGN
-      "1:                                        \n"
+  asm volatile(
+      "1:          \n"
       "movdqu      (%1),%%xmm0                   \n"
       "lea         0x10(%1),%1                   \n"
       "movdqa      %%xmm0,%%xmm1                 \n"
@@ -2201,11 +2197,11 @@
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
 
-               : "+r"(dst_argb),  // %0
-                 "+r"(src_argb),  // %1
-                 "+r"(dst_width)  // %2
-                 ::"memory",
-                 "cc", "xmm0", "xmm1");
+      : "+r"(dst_argb),  // %0
+        "+r"(src_argb),  // %1
+        "+r"(dst_width)  // %2
+      :
+      : "memory", "cc", "xmm0", "xmm1");
 }
 
 // Shuffle table for arranging 2 pixels into pairs for pmaddubsw
@@ -2250,7 +2246,7 @@
       "pextrw      $0x3,%%xmm2,%k4               \n"
 
       LABELALIGN
-      "2:                                        \n"
+      "2:          \n"
       "movdqa      %%xmm2,%%xmm1                 \n"
       "paddd       %%xmm3,%%xmm2                 \n"
       "movq        0x00(%1,%3,4),%%xmm0          \n"
@@ -2270,7 +2266,7 @@
       "jge         2b                            \n"
 
       LABELALIGN
-      "29:                                       \n"
+      "29:         \n"
       "add         $0x1,%2                       \n"
       "jl          99f                           \n"
       "psrlw       $0x9,%%xmm2                   \n"
@@ -2283,8 +2279,7 @@
       "packuswb    %%xmm0,%%xmm0                 \n"
       "movd        %%xmm0,(%0)                   \n"
 
-      LABELALIGN
-      "99:                                       \n"  // clang-format error.
+      LABELALIGN "99:         \n"
 
       : "+r"(dst_argb),    // %0
         "+r"(src_argb),    // %1
@@ -2299,7 +2294,7 @@
 // Divide num by div and return as 16.16 fixed point result.
 int FixedDiv_X86(int num, int div) {
   asm volatile(
-      "cdq                                       \n"
+      "cdq         \n"
       "shld        $0x10,%%eax,%%edx             \n"
       "shl         $0x10,%%eax                   \n"
       "idiv        %1                            \n"
@@ -2313,7 +2308,7 @@
 // Divide num - 1 by div - 1 and return as 16.16 fixed point result.
 int FixedDiv1_X86(int num, int div) {
   asm volatile(
-      "cdq                                       \n"
+      "cdq         \n"
       "shld        $0x10,%%eax,%%edx             \n"
       "shl         $0x10,%%eax                   \n"
       "sub         $0x10001,%%eax                \n"
@@ -2353,7 +2348,7 @@
       "movdqa      %5,%%xmm3                     \n"  // merge shuffler
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movdqu      (%0),%%xmm0                   \n"  // 8 UV row 0
       "movdqu      0x00(%0,%3,1),%%xmm2          \n"  // 8 UV row 1
       "lea         0x10(%0),%0                   \n"
@@ -2386,14 +2381,13 @@
                              int dst_width) {
   asm volatile(
       "vpcmpeqb    %%ymm4,%%ymm4,%%ymm4          \n"  // 01010101
-      "vpsrlw      $0xf,%%ymm4,%%ymm4            \n"
-      "vpackuswb   %%ymm4,%%ymm4,%%ymm4          \n"
+      "vpabsb      %%ymm4,%%ymm4                 \n"
       "vpxor       %%ymm5,%%ymm5,%%ymm5          \n"  // zero
       "vbroadcastf128 %4,%%ymm1                  \n"  // split shuffler
       "vbroadcastf128 %5,%%ymm3                  \n"  // merge shuffler
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%ymm0                   \n"  // 16 UV row 0
       "vmovdqu     0x00(%0,%3,1),%%ymm2          \n"  // 16 UV row 1
       "lea         0x20(%0),%0                   \n"
@@ -2410,7 +2404,7 @@
       "lea         0x10(%1),%1                   \n"  // 8 UV
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
@@ -2435,7 +2429,7 @@
       "movdqa      %3,%%xmm3                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 00112233 (1u1v)
       "movq        2(%0),%%xmm1                  \n"  // 11223344 (1u1v)
       "punpcklbw   %%xmm1,%%xmm0                 \n"  // 0101121223233434 (2u2v)
@@ -2476,7 +2470,7 @@
       "movdqa      %5,%%xmm7                     \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 00112233 (1u1v)
       "movq        2(%0),%%xmm1                  \n"  // 11223344 (1u1v)
       "punpcklbw   %%xmm1,%%xmm0                 \n"  // 0101121223233434 (2u2v)
@@ -2560,7 +2554,7 @@
       "vbroadcastf128 %3,%%ymm3                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"
       "vmovdqu     2(%0),%%xmm1                  \n"
       "vpermq      $0b11011000,%%ymm0,%%ymm0     \n"
@@ -2581,7 +2575,7 @@
       "lea         0x20(%1),%1                   \n"  // 8 uv to 16 uv
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),        // %0
         "+r"(dst_ptr),        // %1
         "+r"(dst_width)       // %2
@@ -2603,7 +2597,7 @@
       "vbroadcastf128 %5,%%ymm7                  \n"
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"
       "vmovdqu     2(%0),%%xmm1                  \n"
       "vpermq      $0b11011000,%%ymm0,%%ymm0     \n"
@@ -2660,7 +2654,7 @@
       "lea         0x20(%1),%1                   \n"  // 8 uv to 16 uv
       "sub         $0x10,%2                      \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
@@ -2683,7 +2677,7 @@
       "pslld       $1,%%xmm4                     \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 0011 (16b, 1u1v)
       "movq        4(%0),%%xmm1                  \n"  // 1122 (16b, 1u1v)
 
@@ -2735,7 +2729,7 @@
       "pslld       $3,%%xmm6                     \n"  // all 8
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "movq        (%0),%%xmm0                   \n"  // 0011 (16b, 1u1v)
       "movq        4(%0),%%xmm1                  \n"  // 1122 (16b, 1u1v)
       "punpcklwd   %%xmm7,%%xmm0                 \n"  // 0011 (near) (32b, 1u1v)
@@ -2825,7 +2819,7 @@
       "vpslld      $1,%%ymm4,%%ymm4              \n"  // all 2
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
       "vmovdqu     (%0),%%xmm0                   \n"  // 00112233 (16b, 1u1v)
       "vmovdqu     4(%0),%%xmm1                  \n"  // 11223344 (16b, 1u1v)
 
@@ -2853,7 +2847,7 @@
       "lea         0x20(%1),%1                   \n"  // 4 uv to 8 uv
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
@@ -2874,7 +2868,7 @@
       "vpslld      $3,%%ymm6,%%ymm6              \n"  // all 8
 
       LABELALIGN
-      "1:                                        \n"
+      "1:          \n"
 
       "vmovdqu     (%0),%%xmm0                   \n"  // 00112233 (16b, 1u1v)
       "vmovdqu     4(%0),%%xmm1                  \n"  // 11223344 (16b, 1u1v)
@@ -2935,7 +2929,7 @@
       "lea         0x20(%1),%1                   \n"  // 4 uv to 8 uv
       "sub         $0x8,%2                       \n"
       "jg          1b                            \n"
-      "vzeroupper                                \n"
+      "vzeroupper  \n"
       : "+r"(src_ptr),                // %0
         "+r"(dst_ptr),                // %1
         "+r"(dst_width)               // %2
diff --git a/source/scale_neon.cc b/source/scale_neon.cc
index ccc7510..0ed3287 100644
--- a/source/scale_neon.cc
+++ b/source/scale_neon.cc
@@ -9,6 +9,7 @@
  */
 
 #include "libyuv/row.h"
+#include "libyuv/scale_row.h"
 
 #ifdef __cplusplus
 namespace libyuv {
@@ -29,7 +30,7 @@
                         int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       // load even pixels into q0, odd into q1
       "vld2.8      {q0, q1}, [%0]!               \n"
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
@@ -50,7 +51,7 @@
                               int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {q0, q1}, [%0]!               \n"  // load 32 pixels
       "subs        %2, %2, #16                   \n"  // 16 processed per loop
       "vrhadd.u8   q0, q0, q1                    \n"  // rounding half add
@@ -72,7 +73,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %0                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0, q1}, [%0]!               \n"  // load row 1 and post inc
       "vld1.8      {q2, q3}, [%1]!               \n"  // load row 2 and post inc
       "subs        %3, %3, #16                   \n"  // 16 processed per loop
@@ -101,7 +102,7 @@
                         int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // src line 0
       "subs        %2, %2, #8                    \n"  // 8 processed per loop
       "vst1.8      {d2}, [%1]!                   \n"
@@ -121,7 +122,7 @@
   const uint8_t* src_ptr2 = src_ptr + src_stride * 2;
   const uint8_t* src_ptr3 = src_ptr + src_stride * 3;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {q0}, [%0]!                   \n"  // load up 16x4
       "vld1.8      {q1}, [%3]!                   \n"
       "vld1.8      {q2}, [%4]!                   \n"
@@ -155,7 +156,7 @@
                          int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // src line 0
       "subs        %2, %2, #24                   \n"
       "vmov        d2, d3                        \n"  // order d0, d1, d2
@@ -175,7 +176,7 @@
   asm volatile(
       "vmov.u8     d24, #3                       \n"
       "add         %3, %0                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // src line 0
       "vld4.8      {d4, d5, d6, d7}, [%3]!       \n"  // src line 1
       "subs        %2, %2, #24                   \n"
@@ -232,7 +233,7 @@
   asm volatile(
       "vmov.u8     d24, #3                       \n"
       "add         %3, %0                        \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d1, d2, d3}, [%0]!       \n"  // src line 0
       "vld4.8      {d4, d5, d6, d7}, [%3]!       \n"  // src line 1
       "subs        %2, %2, #24                   \n"
@@ -283,7 +284,7 @@
   (void)src_stride;
   asm volatile(
       "vld1.8      {q3}, [%3]                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0, d1, d2, d3}, [%0]!       \n"
       "subs        %2, %2, #12                   \n"
       "vtbl.u8     d4, {d0, d1, d2, d3}, d6      \n"
@@ -310,7 +311,7 @@
       "vld1.8      {q14}, [%6]                   \n"
       "vld1.8      {q15}, [%7]                   \n"
       "add         %3, %0                        \n"
-      "1:                                        \n"
+      "1:          \n"
 
       // d0 = 00 40 01 41 02 42 03 43
       // d1 = 10 50 11 51 12 52 13 53
@@ -419,7 +420,7 @@
       "vld1.16     {q13}, [%4]                   \n"
       "vld1.8      {q14}, [%5]                   \n"
       "add         %3, %0                        \n"
-      "1:                                        \n"
+      "1:          \n"
 
       // d0 = 00 40 01 41 02 42 03 43
       // d1 = 10 50 11 51 12 52 13 53
@@ -511,7 +512,7 @@
   asm volatile(
       "vmov.u8     d30, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d4}, [%0]!                   \n"  // 01234567
       "vld1.8      {d5}, [%3]!                   \n"  // 12345678
 
@@ -549,7 +550,7 @@
       "vmov.u16    q15, #3                       \n"
       "vmov.u8     d28, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d4}, [%0]!                   \n"  // 01234567
       "vld1.8      {d5}, [%5]!                   \n"  // 12345678
 
@@ -610,7 +611,7 @@
   asm volatile(
       "vmov.u16    q15, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q1}, [%0]!                   \n"  // 01234567 (16b)
       "vld1.16     {q0}, [%3]!                   \n"  // 12345678 (16b)
 
@@ -646,7 +647,7 @@
   asm volatile(
       "vmov.u16    q15, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"  // 01234567 (16b)
       "vld1.16     {q1}, [%5]!                   \n"  // 12345678 (16b)
 
@@ -697,7 +698,7 @@
   asm volatile(
       "vmov.u16    d31, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"  // 01234567 (16b)
       "vld1.16     {q1}, [%3]!                   \n"  // 12345678 (16b)
 
@@ -742,7 +743,7 @@
       "vmov.u16    d31, #3                       \n"
       "vmov.u32    q14, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {d0}, [%0]!                   \n"  // 0123 (16b)
       "vld1.16     {d1}, [%5]!                   \n"  // 1234 (16b)
       "vmovl.u16   q2, d0                        \n"  // 0123 (32b)
@@ -793,7 +794,7 @@
   asm volatile(
       "vmov.u8     d30, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d4}, [%0]!                   \n"  // 00112233 (1u1v)
       "vld1.8      {d5}, [%3]!                   \n"  // 11223344 (1u1v)
 
@@ -831,7 +832,7 @@
       "vmov.u16    q15, #3                       \n"
       "vmov.u8     d28, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d4}, [%0]!                   \n"  // 00112233 (1u1v)
       "vld1.8      {d5}, [%5]!                   \n"  // 11223344 (1u1v)
 
@@ -892,7 +893,7 @@
   asm volatile(
       "vmov.u16    d30, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q0}, [%0]!                   \n"  // 00112233 (1u1v, 16)
       "vld1.16     {q1}, [%3]!                   \n"  // 11223344 (1u1v, 16)
 
@@ -938,7 +939,7 @@
       "vmov.u16    d30, #3                       \n"
       "vmov.u32    q14, #3                       \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0}, [%0]!                   \n"  // 0011 (1u1v)
       "vld1.8      {d1}, [%5]!                   \n"  // 1122 (1u1v)
       "vmovl.u16   q2, d0                        \n"  // 0011 (1u1v, 32b)
@@ -988,7 +989,7 @@
                       uint16_t* dst_ptr,
                       int src_width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {q1, q2}, [%1]                \n"  // load accumulator
       "vld1.8      {q0}, [%0]!                   \n"  // load 16 bytes
       "vaddw.u8    q2, q2, d1                    \n"  // add
@@ -1035,7 +1036,7 @@
     // x + 4 * dx, x + 5 * dx, x + 6 * dx, x + 7 * dx
       "vadd.s32    q2, q1, q3                    \n"
       "vshl.i32    q0, q3, #1                    \n"  // 8 * dx
-      "1:                                        \n"
+      "1:          \n"
     LOAD2_DATA8_LANE(0)
     LOAD2_DATA8_LANE(1)
     LOAD2_DATA8_LANE(2)
@@ -1080,98 +1081,13 @@
 
 #undef LOAD2_DATA8_LANE
 
-// 16x2 -> 16x1
-void ScaleFilterRows_NEON(uint8_t* dst_ptr,
-                          const uint8_t* src_ptr,
-                          ptrdiff_t src_stride,
-                          int dst_width,
-                          int source_y_fraction) {
-  asm volatile(
-      "cmp         %4, #0                        \n"
-      "beq         100f                          \n"
-      "add         %2, %1                        \n"
-      "cmp         %4, #64                       \n"
-      "beq         75f                           \n"
-      "cmp         %4, #128                      \n"
-      "beq         50f                           \n"
-      "cmp         %4, #192                      \n"
-      "beq         25f                           \n"
-
-      "vdup.8      d5, %4                        \n"
-      "rsb         %4, #256                      \n"
-      "vdup.8      d4, %4                        \n"
-      // General purpose row blend.
-      "1:                                        \n"
-      "vld1.8      {q0}, [%1]!                   \n"
-      "vld1.8      {q1}, [%2]!                   \n"
-      "subs        %3, %3, #16                   \n"
-      "vmull.u8    q13, d0, d4                   \n"
-      "vmull.u8    q14, d1, d4                   \n"
-      "vmlal.u8    q13, d2, d5                   \n"
-      "vmlal.u8    q14, d3, d5                   \n"
-      "vrshrn.u16  d0, q13, #8                   \n"
-      "vrshrn.u16  d1, q14, #8                   \n"
-      "vst1.8      {q0}, [%0]!                   \n"
-      "bgt         1b                            \n"
-      "b           99f                           \n"
-
-      // Blend 25 / 75.
-      "25:                                       \n"
-      "vld1.8      {q0}, [%1]!                   \n"
-      "vld1.8      {q1}, [%2]!                   \n"
-      "subs        %3, %3, #16                   \n"
-      "vrhadd.u8   q0, q1                        \n"
-      "vrhadd.u8   q0, q1                        \n"
-      "vst1.8      {q0}, [%0]!                   \n"
-      "bgt         25b                           \n"
-      "b           99f                           \n"
-
-      // Blend 50 / 50.
-      "50:                                       \n"
-      "vld1.8      {q0}, [%1]!                   \n"
-      "vld1.8      {q1}, [%2]!                   \n"
-      "subs        %3, %3, #16                   \n"
-      "vrhadd.u8   q0, q1                        \n"
-      "vst1.8      {q0}, [%0]!                   \n"
-      "bgt         50b                           \n"
-      "b           99f                           \n"
-
-      // Blend 75 / 25.
-      "75:                                       \n"
-      "vld1.8      {q1}, [%1]!                   \n"
-      "vld1.8      {q0}, [%2]!                   \n"
-      "subs        %3, %3, #16                   \n"
-      "vrhadd.u8   q0, q1                        \n"
-      "vrhadd.u8   q0, q1                        \n"
-      "vst1.8      {q0}, [%0]!                   \n"
-      "bgt         75b                           \n"
-      "b           99f                           \n"
-
-      // Blend 100 / 0 - Copy row unchanged.
-      "100:                                      \n"
-      "vld1.8      {q0}, [%1]!                   \n"
-      "subs        %3, %3, #16                   \n"
-      "vst1.8      {q0}, [%0]!                   \n"
-      "bgt         100b                          \n"
-
-      "99:                                       \n"
-      "vst1.8      {d1[7]}, [%0]                 \n"
-      : "+r"(dst_ptr),           // %0
-        "+r"(src_ptr),           // %1
-        "+r"(src_stride),        // %2
-        "+r"(dst_width),         // %3
-        "+r"(source_y_fraction)  // %4
-      :
-      : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc");
-}
-
 void ScaleARGBRowDown2_NEON(const uint8_t* src_ptr,
                             ptrdiff_t src_stride,
                             uint8_t* dst,
                             int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.32     {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.32     {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB
       "subs        %2, %2, #8                    \n"  // 8 processed per loop
@@ -1199,7 +1115,7 @@
                                   int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld4.32     {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.32     {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB
       "subs        %2, %2, #8                    \n"  // 8 processed per loop
@@ -1222,7 +1138,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld4.8      {d0, d2, d4, d6}, [%0]!       \n"  // load 8 ARGB pixels.
       "vld4.8      {d1, d3, d5, d7}, [%0]!       \n"  // load next 8 ARGB
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -1260,7 +1176,7 @@
   (void)src_stride;
   asm volatile(
       "mov         r12, %3, lsl #2               \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.32     {d0[0]}, [%0], r12            \n"
       "vld1.32     {d0[1]}, [%0], r12            \n"
       "vld1.32     {d1[0]}, [%0], r12            \n"
@@ -1285,7 +1201,7 @@
   asm volatile(
       "mov         r12, %4, lsl #2               \n"
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld1.8      {d0}, [%0], r12               \n"  // 4 2x2 blocks -> 2x1
       "vld1.8      {d1}, [%1], r12               \n"
       "vld1.8      {d2}, [%0], r12               \n"
@@ -1331,7 +1247,7 @@
   int tmp;
   const uint8_t* src_tmp = src_argb;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       // clang-format off
       LOAD1_DATA32_LANE(d0, 0)
       LOAD1_DATA32_LANE(d0, 1)
@@ -1384,7 +1300,7 @@
       "vmov.i16    q15, #0x7f                    \n"  // 0x7F
     // x         , x + 1 * dx, x + 2 * dx, x + 3 * dx
       "vadd.s32    q8, q1, q0                    \n"
-      "1:                                        \n"
+      "1:          \n"
     // d0, d1: a
     // d2, d3: b
     LOAD2_DATA32_LANE(d0, d2, 0)
@@ -1434,7 +1350,7 @@
                           int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.16     {d0, d2}, [%0]!               \n"  // load 8 UV pixels.
       "vld2.16     {d1, d3}, [%0]!               \n"  // load next 8 UV
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
@@ -1453,7 +1369,7 @@
                                 int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld2.16     {d0, d2}, [%0]!               \n"  // load 8 UV pixels.
       "vld2.16     {d1, d3}, [%0]!               \n"  // load next 8 UV
       "subs        %2, %2, #8                    \n"  // 8 processed per loop.
@@ -1474,7 +1390,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "vld2.8      {d0, d2}, [%0]!               \n"  // load 8 UV pixels.
       "vld2.8      {d1, d3}, [%0]!               \n"  // load next 8 UV
       "subs        %3, %3, #8                    \n"  // 8 processed per loop.
@@ -1507,7 +1423,7 @@
   const uint8_t* src3_ptr = src_ptr + src_stepx * 6;
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "vld1.16     {d0[0]}, [%0], %6             \n"
       "vld1.16     {d0[1]}, [%1], %6             \n"
       "vld1.16     {d0[2]}, [%2], %6             \n"
diff --git a/source/scale_neon64.cc b/source/scale_neon64.cc
index 7c07238..e7f9f6c 100644
--- a/source/scale_neon64.cc
+++ b/source/scale_neon64.cc
@@ -27,7 +27,7 @@
                         int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       // load even pixels into v0, odd into v1
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
@@ -38,7 +38,7 @@
         "+r"(dst),       // %1
         "+r"(dst_width)  // %2
       :
-      : "v0", "v1"  // Clobber List
+      : "memory", "cc", "v0", "v1"  // Clobber List
   );
 }
 
@@ -49,7 +49,7 @@
                               int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       // load even pixels into v0, odd into v1
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"
       "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
@@ -61,7 +61,7 @@
         "+r"(dst),       // %1
         "+r"(dst_width)  // %2
       :
-      : "v0", "v1"  // Clobber List
+      : "memory", "cc", "v0", "v1"  // Clobber List
   );
 }
 
@@ -73,7 +73,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.16b, v1.16b}, [%0], #32   \n"  // load row 1 and post inc
       "ld1         {v2.16b, v3.16b}, [%1], #32   \n"  // load row 2 and post inc
       "subs        %w3, %w3, #16                 \n"  // 16 processed per loop
@@ -92,7 +92,7 @@
         "+r"(dst),         // %2
         "+r"(dst_width)    // %3
       :
-      : "v0", "v1", "v2", "v3"  // Clobber List
+      : "memory", "cc", "v0", "v1", "v2", "v3"  // Clobber List
   );
 }
 
@@ -102,17 +102,17 @@
                         int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // src line 0
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
+      "1:          \n"
+      "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // src line 0
+      "subs        %w2, %w2, #16                 \n"  // 16 processed per loop
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "st1         {v2.8b}, [%1], #8             \n"
+      "st1         {v2.16b}, [%1], #16           \n"
       "b.gt        1b                            \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
         "+r"(dst_width)  // %2
       :
-      : "v0", "v1", "v2", "v3", "memory", "cc");
+      : "memory", "cc", "v0", "v1", "v2", "v3");
 }
 
 void ScaleRowDown4Box_NEON(const uint8_t* src_ptr,
@@ -123,23 +123,27 @@
   const uint8_t* src_ptr2 = src_ptr + src_stride * 2;
   const uint8_t* src_ptr3 = src_ptr + src_stride * 3;
   asm volatile(
-      "1:                                        \n"
-      "ld1         {v0.16b}, [%0], #16           \n"  // load up 16x4
-      "ld1         {v1.16b}, [%2], #16           \n"
-      "ld1         {v2.16b}, [%3], #16           \n"
-      "ld1         {v3.16b}, [%4], #16           \n"
-      "subs        %w5, %w5, #4                  \n"
+      "1:          \n"
+      "ldp         q0, q4, [%0], #32             \n"  // load up 16x8
+      "ldp         q1, q5, [%2], #32             \n"
+      "ldp         q2, q6, [%3], #32             \n"
+      "ldp         q3, q7, [%4], #32             \n"
+      "subs        %w5, %w5, #8                  \n"
       "uaddlp      v0.8h, v0.16b                 \n"
+      "uaddlp      v4.8h, v4.16b                 \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
       "uadalp      v0.8h, v1.16b                 \n"
+      "uadalp      v4.8h, v5.16b                 \n"
       "prfm        pldl1keep, [%2, 448]          \n"
       "uadalp      v0.8h, v2.16b                 \n"
+      "uadalp      v4.8h, v6.16b                 \n"
       "prfm        pldl1keep, [%3, 448]          \n"
       "uadalp      v0.8h, v3.16b                 \n"
+      "uadalp      v4.8h, v7.16b                 \n"
       "prfm        pldl1keep, [%4, 448]          \n"
-      "addp        v0.8h, v0.8h, v0.8h           \n"
+      "addp        v0.8h, v0.8h, v4.8h           \n"
       "rshrn       v0.8b, v0.8h, #4              \n"  // divide by 16 w/rounding
-      "st1         {v0.s}[0], [%1], #4           \n"
+      "str         d0, [%1], #8                  \n"
       "b.gt        1b                            \n"
       : "+r"(src_ptr),   // %0
         "+r"(dst_ptr),   // %1
@@ -148,30 +152,45 @@
         "+r"(src_ptr3),  // %4
         "+r"(dst_width)  // %5
       :
-      : "v0", "v1", "v2", "v3", "memory", "cc");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
 }
 
-// Down scale from 4 to 3 pixels. Use the neon multilane read/write
-// to load up the every 4th pixel into a 4 different registers.
-// Point samples 32 pixels to 24 pixels.
+static const uvec8 kShuf34_0 = {
+    0, 1, 3, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20,
+};
+static const uvec8 kShuf34_1 = {
+    5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20, 21, 23, 24, 25,
+};
+static const uvec8 kShuf34_2 = {
+    11, 12, 13, 15, 16, 17, 19, 20, 21, 23, 24, 25, 27, 28, 29, 31,
+};
+
+// Down scale from 4 to 3 pixels. Point samples 64 pixels to 48 pixels.
 void ScaleRowDown34_NEON(const uint8_t* src_ptr,
                          ptrdiff_t src_stride,
                          uint8_t* dst_ptr,
                          int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // src line 0
-      "subs        %w2, %w2, #24                 \n"
-      "orr         v2.16b, v3.16b, v3.16b        \n"  // order v0,v1,v2
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "st3         {v0.8b,v1.8b,v2.8b}, [%1], #24 \n"
+      "ld1         {v29.16b}, [%[kShuf34_0]]     \n"
+      "ld1         {v30.16b}, [%[kShuf34_1]]     \n"
+      "ld1         {v31.16b}, [%[kShuf34_2]]     \n"
+      "1:          \n"
+      "ld1         {v0.16b,v1.16b,v2.16b,v3.16b}, [%[src_ptr]], #64 \n"
+      "subs        %w[width], %w[width], #48     \n"
+      "tbl         v0.16b, {v0.16b, v1.16b}, v29.16b \n"
+      "prfm        pldl1keep, [%[src_ptr], 448]  \n"
+      "tbl         v1.16b, {v1.16b, v2.16b}, v30.16b \n"
+      "tbl         v2.16b, {v2.16b, v3.16b}, v31.16b \n"
+      "st1         {v0.16b,v1.16b,v2.16b}, [%[dst_ptr]], #48 \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),   // %0
-        "+r"(dst_ptr),   // %1
-        "+r"(dst_width)  // %2
-      :
-      : "v0", "v1", "v2", "v3", "memory", "cc");
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [dst_ptr] "+r"(dst_ptr),      // %[dst_ptr]
+        [width] "+r"(dst_width)       // %[width]
+      : [kShuf34_0] "r"(&kShuf34_0),  // %[kShuf34_0]
+        [kShuf34_1] "r"(&kShuf34_1),  // %[kShuf34_1]
+        [kShuf34_2] "r"(&kShuf34_2)   // %[kShuf34_2]
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v29", "v30", "v31");
 }
 
 void ScaleRowDown34_0_Box_NEON(const uint8_t* src_ptr,
@@ -179,12 +198,13 @@
                                uint8_t* dst_ptr,
                                int dst_width) {
   asm volatile(
-      "movi        v20.8b, #3                    \n"
+      "movi        v24.16b, #3                   \n"
       "add         %3, %3, %0                    \n"
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // src line 0
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%3], #32 \n"  // src line 1
-      "subs        %w2, %w2, #24                 \n"
+
+      "1:          \n"
+      "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // src line 0
+      "ld4         {v4.16b,v5.16b,v6.16b,v7.16b}, [%3], #64 \n"  // src line 1
+      "subs        %w2, %w2, #48                 \n"
 
       // filter src line 0 with src line 1
       // expand chars to shorts to allow for room
@@ -193,12 +213,20 @@
       "ushll       v17.8h, v5.8b, #0             \n"
       "ushll       v18.8h, v6.8b, #0             \n"
       "ushll       v19.8h, v7.8b, #0             \n"
+      "ushll2      v20.8h, v4.16b, #0            \n"
+      "ushll2      v21.8h, v5.16b, #0            \n"
+      "ushll2      v22.8h, v6.16b, #0            \n"
+      "ushll2      v23.8h, v7.16b, #0            \n"
 
       // 3 * line_0 + line_1
-      "umlal       v16.8h, v0.8b, v20.8b         \n"
-      "umlal       v17.8h, v1.8b, v20.8b         \n"
-      "umlal       v18.8h, v2.8b, v20.8b         \n"
-      "umlal       v19.8h, v3.8b, v20.8b         \n"
+      "umlal       v16.8h, v0.8b, v24.8b         \n"
+      "umlal       v17.8h, v1.8b, v24.8b         \n"
+      "umlal       v18.8h, v2.8b, v24.8b         \n"
+      "umlal       v19.8h, v3.8b, v24.8b         \n"
+      "umlal2      v20.8h, v0.16b, v24.16b       \n"
+      "umlal2      v21.8h, v1.16b, v24.16b       \n"
+      "umlal2      v22.8h, v2.16b, v24.16b       \n"
+      "umlal2      v23.8h, v3.16b, v24.16b       \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
 
       // (3 * line_0 + line_1 + 2) >> 2
@@ -206,22 +234,32 @@
       "uqrshrn     v1.8b, v17.8h, #2             \n"
       "uqrshrn     v2.8b, v18.8h, #2             \n"
       "uqrshrn     v3.8b, v19.8h, #2             \n"
+      "uqrshrn2    v0.16b, v20.8h, #2            \n"
+      "uqrshrn2    v1.16b, v21.8h, #2            \n"
+      "uqrshrn2    v2.16b, v22.8h, #2            \n"
+      "uqrshrn2    v3.16b, v23.8h, #2            \n"
       "prfm        pldl1keep, [%3, 448]          \n"
 
       // a0 = (src[0] * 3 + s[1] * 1 + 2) >> 2
       "ushll       v16.8h, v1.8b, #0             \n"
-      "umlal       v16.8h, v0.8b, v20.8b         \n"
+      "ushll2      v17.8h, v1.16b, #0            \n"
+      "umlal       v16.8h, v0.8b, v24.8b         \n"
+      "umlal2      v17.8h, v0.16b, v24.16b       \n"
       "uqrshrn     v0.8b, v16.8h, #2             \n"
+      "uqrshrn2    v0.16b, v17.8h, #2            \n"
 
       // a1 = (src[1] * 1 + s[2] * 1 + 1) >> 1
-      "urhadd      v1.8b, v1.8b, v2.8b           \n"
+      "urhadd      v1.16b, v1.16b, v2.16b        \n"
 
       // a2 = (src[2] * 1 + s[3] * 3 + 2) >> 2
       "ushll       v16.8h, v2.8b, #0             \n"
-      "umlal       v16.8h, v3.8b, v20.8b         \n"
+      "ushll2      v17.8h, v2.16b, #0            \n"
+      "umlal       v16.8h, v3.8b, v24.8b         \n"
+      "umlal2      v17.8h, v3.16b, v24.16b       \n"
       "uqrshrn     v2.8b, v16.8h, #2             \n"
+      "uqrshrn2    v2.16b, v17.8h, #2            \n"
 
-      "st3         {v0.8b,v1.8b,v2.8b}, [%1], #24 \n"
+      "st3         {v0.16b,v1.16b,v2.16b}, [%1], #48 \n"
 
       "b.gt        1b                            \n"
       : "+r"(src_ptr),    // %0
@@ -229,8 +267,8 @@
         "+r"(dst_width),  // %2
         "+r"(src_stride)  // %3
       :
-      : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18",
-        "v19", "v20", "memory", "cc");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
+        "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24");
 }
 
 void ScaleRowDown34_1_Box_NEON(const uint8_t* src_ptr,
@@ -238,53 +276,57 @@
                                uint8_t* dst_ptr,
                                int dst_width) {
   asm volatile(
-      "movi        v20.8b, #3                    \n"
+      "movi        v20.16b, #3                   \n"
       "add         %3, %3, %0                    \n"
-      "1:                                        \n"
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"  // src line 0
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%3], #32 \n"  // src line 1
-      "subs        %w2, %w2, #24                 \n"
+
+      "1:          \n"
+      "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // src line 0
+      "ld4         {v4.16b,v5.16b,v6.16b,v7.16b}, [%3], #64 \n"  // src line 1
+      "subs        %w2, %w2, #48                 \n"
       // average src line 0 with src line 1
-      "urhadd      v0.8b, v0.8b, v4.8b           \n"
-      "urhadd      v1.8b, v1.8b, v5.8b           \n"
-      "urhadd      v2.8b, v2.8b, v6.8b           \n"
-      "urhadd      v3.8b, v3.8b, v7.8b           \n"
+      "urhadd      v0.16b, v0.16b, v4.16b        \n"
+      "urhadd      v1.16b, v1.16b, v5.16b        \n"
+      "urhadd      v2.16b, v2.16b, v6.16b        \n"
+      "urhadd      v3.16b, v3.16b, v7.16b        \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
 
       // a0 = (src[0] * 3 + s[1] * 1 + 2) >> 2
       "ushll       v4.8h, v1.8b, #0              \n"
+      "ushll2      v5.8h, v1.16b, #0             \n"
       "umlal       v4.8h, v0.8b, v20.8b          \n"
+      "umlal2      v5.8h, v0.16b, v20.16b        \n"
       "uqrshrn     v0.8b, v4.8h, #2              \n"
+      "uqrshrn2    v0.16b, v5.8h, #2             \n"
       "prfm        pldl1keep, [%3, 448]          \n"
 
       // a1 = (src[1] * 1 + s[2] * 1 + 1) >> 1
-      "urhadd      v1.8b, v1.8b, v2.8b           \n"
+      "urhadd      v1.16b, v1.16b, v2.16b        \n"
 
       // a2 = (src[2] * 1 + s[3] * 3 + 2) >> 2
       "ushll       v4.8h, v2.8b, #0              \n"
+      "ushll2      v5.8h, v2.16b, #0             \n"
       "umlal       v4.8h, v3.8b, v20.8b          \n"
+      "umlal2      v5.8h, v3.16b, v20.16b        \n"
       "uqrshrn     v2.8b, v4.8h, #2              \n"
+      "uqrshrn2    v2.16b, v5.8h, #2             \n"
 
-      "st3         {v0.8b,v1.8b,v2.8b}, [%1], #24 \n"
+      "st3         {v0.16b,v1.16b,v2.16b}, [%1], #48 \n"
       "b.gt        1b                            \n"
       : "+r"(src_ptr),    // %0
         "+r"(dst_ptr),    // %1
         "+r"(dst_width),  // %2
         "+r"(src_stride)  // %3
       :
-      : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20", "memory", "cc");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20");
 }
 
 static const uvec8 kShuf38 = {0,  3,  6,  8,  11, 14, 16, 19,
                               22, 24, 27, 30, 0,  0,  0,  0};
-static const uvec8 kShuf38_2 = {0,  16, 32, 2,  18, 33, 4, 20,
-                                34, 6,  22, 35, 0,  0,  0, 0};
-static const vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12,
-                                   65536 / 12, 65536 / 12, 65536 / 12,
-                                   65536 / 12, 65536 / 12};
-static const vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18,
-                                   65536 / 18, 65536 / 18, 65536 / 18,
-                                   65536 / 18, 65536 / 18};
+static const vec16 kMult38_Div664 = {
+    65536 / 12, 65536 / 12, 65536 / 8, 65536 / 12, 65536 / 12, 65536 / 8, 0, 0};
+static const vec16 kMult38_Div996 = {65536 / 18, 65536 / 18, 65536 / 12,
+                                     65536 / 18, 65536 / 18, 65536 / 12,
+                                     0,          0};
 
 // 32 -> 12
 void ScaleRowDown38_NEON(const uint8_t* src_ptr,
@@ -293,246 +335,162 @@
                          int dst_width) {
   (void)src_stride;
   asm volatile(
-      "ld1         {v3.16b}, [%3]                \n"
-      "1:                                        \n"
-      "ld1         {v0.16b,v1.16b}, [%0], #32    \n"
-      "subs        %w2, %w2, #12                 \n"
-      "tbl         v2.16b, {v0.16b,v1.16b}, v3.16b \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "st1         {v2.8b}, [%1], #8             \n"
-      "st1         {v2.s}[2], [%1], #4           \n"
+      "ld1         {v3.16b}, [%[kShuf38]]        \n"
+      "subs        %w[width], %w[width], #12     \n"
+      "b.eq        2f                            \n"
+
+      "1:          \n"
+      "ldp         q0, q1, [%[src_ptr]], #32     \n"
+      "subs        %w[width], %w[width], #12     \n"
+      "tbl         v2.16b, {v0.16b, v1.16b}, v3.16b \n"
+      "prfm        pldl1keep, [%[src_ptr], 448]  \n"  // prefetch 7 lines ahead
+      "str         q2, [%[dst_ptr]]              \n"
+      "add         %[dst_ptr], %[dst_ptr], #12   \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),   // %0
-        "+r"(dst_ptr),   // %1
-        "+r"(dst_width)  // %2
-      : "r"(&kShuf38)    // %3
-      : "v0", "v1", "v2", "v3", "memory", "cc");
+
+      // Store exactly 12 bytes on the final iteration to avoid writing past
+      // the end of the array.
+      "2:          \n"
+      "ldp         q0, q1, [%[src_ptr]]          \n"
+      "tbl         v2.16b, {v0.16b, v1.16b}, v3.16b \n"
+      "st1         {v2.8b}, [%[dst_ptr]], #8     \n"
+      "st1         {v2.s}[2], [%[dst_ptr]]       \n"
+      : [src_ptr] "+r"(src_ptr),  // %[src_ptr]
+        [dst_ptr] "+r"(dst_ptr),  // %[dst_ptr]
+        [width] "+r"(dst_width)   // %[width]
+      : [kShuf38] "r"(&kShuf38)   // %[kShuf38]
+      : "memory", "cc", "v0", "v1", "v2", "v3");
 }
 
-// 32x3 -> 12x1
-void OMITFP ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr,
-                                      ptrdiff_t src_stride,
-                                      uint8_t* dst_ptr,
-                                      int dst_width) {
-  const uint8_t* src_ptr1 = src_ptr + src_stride * 2;
-  ptrdiff_t tmp_src_stride = src_stride;
+static const uvec8 kScaleRowDown38_3_BoxIndices1[] = {
+    0, 1, 6, 7, 12, 13, 16, 17, 22, 23, 28, 29, 255, 255, 255, 255};
+static const uvec8 kScaleRowDown38_3_BoxIndices2[] = {
+    2, 3, 8, 9, 14, 15, 18, 19, 24, 25, 30, 31, 255, 255, 255, 255};
+static const uvec8 kScaleRowDown38_3_BoxIndices3[] = {
+    4, 5, 10, 11, 255, 255, 20, 21, 26, 27, 255, 255, 255, 255, 255, 255};
+static const uvec8 kScaleRowDown38_NarrowIndices[] = {
+    0, 2, 4, 6, 8, 10, 16, 18, 20, 22, 24, 26, 255, 255, 255, 255};
 
+void ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr,
+                               ptrdiff_t src_stride,
+                               uint8_t* dst_ptr,
+                               int dst_width) {
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
+  const uint8_t* src_ptr2 = src_ptr + src_stride * 2;
   asm volatile(
-      "ld1         {v29.8h}, [%5]                \n"
-      "ld1         {v30.16b}, [%6]               \n"
-      "ld1         {v31.8h}, [%7]                \n"
-      "add         %2, %2, %0                    \n"
-      "1:                                        \n"
+      "ld1         {v27.16b}, [%[tblArray1]]     \n"
+      "ld1         {v28.16b}, [%[tblArray2]]     \n"
+      "ld1         {v29.16b}, [%[tblArray3]]     \n"
+      "ld1         {v31.16b}, [%[tblArray4]]     \n"
+      "ld1         {v30.16b}, [%[div996]]        \n"
 
-      // 00 40 01 41 02 42 03 43
-      // 10 50 11 51 12 52 13 53
-      // 20 60 21 61 22 62 23 63
-      // 30 70 31 71 32 72 33 73
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%2], #32 \n"
-      "ld4         {v16.8b,v17.8b,v18.8b,v19.8b}, [%3], #32 \n"
-      "subs        %w4, %w4, #12                 \n"
+      "1:          \n"
+      "ldp         q20, q0, [%[src_ptr]], #32    \n"
+      "ldp         q21, q1, [%[src_ptr1]], #32   \n"
+      "ldp         q22, q2, [%[src_ptr2]], #32   \n"
 
-      // Shuffle the input data around to get align the data
-      //  so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7
-      // 00 10 01 11 02 12 03 13
-      // 40 50 41 51 42 52 43 53
-      "trn1        v20.8b, v0.8b, v1.8b          \n"
-      "trn2        v21.8b, v0.8b, v1.8b          \n"
-      "trn1        v22.8b, v4.8b, v5.8b          \n"
-      "trn2        v23.8b, v4.8b, v5.8b          \n"
-      "trn1        v24.8b, v16.8b, v17.8b        \n"
-      "trn2        v25.8b, v16.8b, v17.8b        \n"
+      "subs        %w[width], %w[width], #12     \n"
 
-      // 20 30 21 31 22 32 23 33
-      // 60 70 61 71 62 72 63 73
-      "trn1        v0.8b, v2.8b, v3.8b           \n"
-      "trn2        v1.8b, v2.8b, v3.8b           \n"
-      "trn1        v4.8b, v6.8b, v7.8b           \n"
-      "trn2        v5.8b, v6.8b, v7.8b           \n"
-      "trn1        v16.8b, v18.8b, v19.8b        \n"
-      "trn2        v17.8b, v18.8b, v19.8b        \n"
+      // Add across strided rows first.
+      "uaddl       v23.8h, v20.8b, v21.8b        \n"
+      "uaddl       v3.8h, v0.8b, v1.8b           \n"
+      "uaddl2      v24.8h, v20.16b, v21.16b      \n"
+      "uaddl2      v4.8h, v0.16b, v1.16b         \n"
 
-      // 00+10 01+11 02+12 03+13
-      // 40+50 41+51 42+52 43+53
-      "uaddlp      v20.4h, v20.8b                \n"
-      "uaddlp      v21.4h, v21.8b                \n"
-      "uaddlp      v22.4h, v22.8b                \n"
-      "uaddlp      v23.4h, v23.8b                \n"
-      "uaddlp      v24.4h, v24.8b                \n"
-      "uaddlp      v25.4h, v25.8b                \n"
+      "uaddw       v23.8h, v23.8h, v22.8b        \n"
+      "uaddw       v3.8h, v3.8h, v2.8b           \n"
+      "uaddw2      v24.8h, v24.8h, v22.16b       \n"  // abcdefgh ...
+      "uaddw2      v4.8h, v4.8h, v2.16b          \n"
 
-      // 60+70 61+71 62+72 63+73
-      "uaddlp      v1.4h, v1.8b                  \n"
-      "uaddlp      v5.4h, v5.8b                  \n"
-      "uaddlp      v17.4h, v17.8b                \n"
+      // Permute groups of {three,three,two} into separate vectors to sum.
+      "tbl         v20.16b, {v23.16b, v24.16b}, v27.16b \n"  // a d g ...
+      "tbl         v0.16b, {v3.16b, v4.16b}, v27.16b \n"
+      "tbl         v21.16b, {v23.16b, v24.16b}, v28.16b \n"  // b e h ...
+      "tbl         v1.16b, {v3.16b, v4.16b}, v28.16b \n"
+      "tbl         v22.16b, {v23.16b, v24.16b}, v29.16b \n"  // c f 0...
+      "tbl         v2.16b, {v3.16b, v4.16b}, v29.16b \n"
 
-      // combine source lines
-      "add         v20.4h, v20.4h, v22.4h        \n"
-      "add         v21.4h, v21.4h, v23.4h        \n"
-      "add         v20.4h, v20.4h, v24.4h        \n"
-      "add         v21.4h, v21.4h, v25.4h        \n"
-      "add         v2.4h, v1.4h, v5.4h           \n"
-      "add         v2.4h, v2.4h, v17.4h          \n"
+      "add         v23.8h, v20.8h, v21.8h        \n"
+      "add         v3.8h, v0.8h, v1.8h           \n"
+      "add         v24.8h, v23.8h, v22.8h        \n"  // a+b+c d+e+f g+h
+      "add         v4.8h, v3.8h, v2.8h           \n"
 
-      // dst_ptr[3] = (s[6 + st * 0] + s[7 + st * 0]
-      //             + s[6 + st * 1] + s[7 + st * 1]
-      //             + s[6 + st * 2] + s[7 + st * 2]) / 6
-      "sqrdmulh    v2.8h, v2.8h, v29.8h          \n"
-      "xtn         v2.8b,  v2.8h                 \n"
-
-      // Shuffle 2,3 reg around so that 2 can be added to the
-      //  0,1 reg and 3 can be added to the 4,5 reg. This
-      //  requires expanding from u8 to u16 as the 0,1 and 4,5
-      //  registers are already expanded. Then do transposes
-      //  to get aligned.
-      // xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33
-      "ushll       v16.8h, v16.8b, #0            \n"
-      "uaddl       v0.8h, v0.8b, v4.8b           \n"
-
-      // combine source lines
-      "add         v0.8h, v0.8h, v16.8h          \n"
-
-      // xx 20 xx 21 xx 22 xx 23
-      // xx 30 xx 31 xx 32 xx 33
-      "trn1        v1.8h, v0.8h, v0.8h           \n"
-      "trn2        v4.8h, v0.8h, v0.8h           \n"
-      "xtn         v0.4h, v1.4s                  \n"
-      "xtn         v4.4h, v4.4s                  \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-
-      // 0+1+2, 3+4+5
-      "add         v20.8h, v20.8h, v0.8h         \n"
-      "add         v21.8h, v21.8h, v4.8h         \n"
-      "prfm        pldl1keep, [%2, 448]          \n"
-
-      // Need to divide, but can't downshift as the the value
-      //  isn't a power of 2. So multiply by 65536 / n
-      //  and take the upper 16 bits.
-      "sqrdmulh    v0.8h, v20.8h, v31.8h         \n"
-      "sqrdmulh    v1.8h, v21.8h, v31.8h         \n"
-      "prfm        pldl1keep, [%3, 448]          \n"
-
-      // Align for table lookup, vtbl requires registers to be adjacent
-      "tbl         v3.16b, {v0.16b, v1.16b, v2.16b}, v30.16b \n"
-
-      "st1         {v3.8b}, [%1], #8             \n"
-      "st1         {v3.s}[2], [%1], #4           \n"
+      "sqrdmulh    v24.8h, v24.8h, v30.8h        \n"  // v /= {9,9,6}
+      "sqrdmulh    v25.8h, v4.8h, v30.8h         \n"
+      "tbl         v21.16b, {v24.16b, v25.16b}, v31.16b \n"  // Narrow.
+      "st1         {v21.d}[0], [%[dst_ptr]], #8  \n"
+      "st1         {v21.s}[2], [%[dst_ptr]], #4  \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),         // %0
-        "+r"(dst_ptr),         // %1
-        "+r"(tmp_src_stride),  // %2
-        "+r"(src_ptr1),        // %3
-        "+r"(dst_width)        // %4
-      : "r"(&kMult38_Div6),    // %5
-        "r"(&kShuf38_2),       // %6
-        "r"(&kMult38_Div9)     // %7
-      : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18",
-        "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v29", "v30", "v31",
-        "memory", "cc");
+      : [src_ptr] "+r"(src_ptr),                         // %[src_ptr]
+        [dst_ptr] "+r"(dst_ptr),                         // %[dst_ptr]
+        [src_ptr1] "+r"(src_ptr1),                       // %[src_ptr1]
+        [src_ptr2] "+r"(src_ptr2),                       // %[src_ptr2]
+        [width] "+r"(dst_width)                          // %[width]
+      : [div996] "r"(&kMult38_Div996),                   // %[div996]
+        [tblArray1] "r"(kScaleRowDown38_3_BoxIndices1),  // %[tblArray1]
+        [tblArray2] "r"(kScaleRowDown38_3_BoxIndices2),  // %[tblArray2]
+        [tblArray3] "r"(kScaleRowDown38_3_BoxIndices3),  // %[tblArray3]
+        [tblArray4] "r"(kScaleRowDown38_NarrowIndices)   // %[tblArray4]
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v20", "v21", "22", "23",
+        "24", "v27", "v28", "v29", "v30", "v31");
 }
 
-// 32x2 -> 12x1
+static const uvec8 kScaleRowDown38_2_BoxIndices1[] = {
+    0, 1, 3, 4, 6, 7, 8, 9, 11, 12, 14, 15, 255, 255, 255, 255};
+static const uvec8 kScaleRowDown38_2_BoxIndices2[] = {
+    2, 18, 5, 21, 255, 255, 10, 26, 13, 29, 255, 255, 255, 255, 255, 255};
+
 void ScaleRowDown38_2_Box_NEON(const uint8_t* src_ptr,
                                ptrdiff_t src_stride,
                                uint8_t* dst_ptr,
                                int dst_width) {
-  // TODO(fbarchard): use src_stride directly for clang 3.5+.
-  ptrdiff_t tmp_src_stride = src_stride;
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
   asm volatile(
-      "ld1         {v30.8h}, [%4]                \n"
-      "ld1         {v31.16b}, [%5]               \n"
-      "add         %2, %2, %0                    \n"
-      "1:                                        \n"
+      "ld1         {v28.16b}, [%[tblArray1]]     \n"
+      "ld1         {v29.16b}, [%[tblArray2]]     \n"
+      "ld1         {v31.16b}, [%[tblArray3]]     \n"
+      "ld1         {v30.8h}, [%[div664]]         \n"
 
-      // 00 40 01 41 02 42 03 43
-      // 10 50 11 51 12 52 13 53
-      // 20 60 21 61 22 62 23 63
-      // 30 70 31 71 32 72 33 73
-      "ld4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n"
-      "ld4         {v4.8b,v5.8b,v6.8b,v7.8b}, [%2], #32 \n"
-      "subs        %w3, %w3, #12                 \n"
+      "1:          \n"
+      "ldp         q20, q0, [%[src_ptr]], #32    \n"  // abcdefgh ...
+      "ldp         q21, q1, [%[src_ptr1]], #32   \n"  // ijklmnop ...
+      "subs        %w[width], %w[width], #12     \n"
 
-      // Shuffle the input data around to get align the data
-      //  so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7
-      // 00 10 01 11 02 12 03 13
-      // 40 50 41 51 42 52 43 53
-      "trn1        v16.8b, v0.8b, v1.8b          \n"
-      "trn2        v17.8b, v0.8b, v1.8b          \n"
-      "trn1        v18.8b, v4.8b, v5.8b          \n"
-      "trn2        v19.8b, v4.8b, v5.8b          \n"
+      // Permute into groups of six values (three pairs) to be summed.
+      "tbl         v22.16b, {v20.16b}, v28.16b   \n"  // abdegh ...
+      "tbl         v2.16b, {v0.16b}, v28.16b     \n"
+      "tbl         v23.16b, {v21.16b}, v28.16b   \n"  // ijlmop ...
+      "tbl         v3.16b, {v1.16b}, v28.16b     \n"
+      "tbl         v24.16b, {v20.16b, v21.16b}, v29.16b \n"  // ckfn00 ...
+      "tbl         v4.16b, {v0.16b, v1.16b}, v29.16b \n"
 
-      // 20 30 21 31 22 32 23 33
-      // 60 70 61 71 62 72 63 73
-      "trn1        v0.8b, v2.8b, v3.8b           \n"
-      "trn2        v1.8b, v2.8b, v3.8b           \n"
-      "trn1        v4.8b, v6.8b, v7.8b           \n"
-      "trn2        v5.8b, v6.8b, v7.8b           \n"
+      "uaddlp      v22.8h, v22.16b               \n"  // a+b d+e g+h ...
+      "uaddlp      v2.8h, v2.16b                 \n"
+      "uaddlp      v23.8h, v23.16b               \n"  // i+j l+m o+p ...
+      "uaddlp      v3.8h, v3.16b                 \n"
+      "uaddlp      v24.8h, v24.16b               \n"  // c+k f+n   0 ...
+      "uaddlp      v4.8h, v4.16b                 \n"
+      "add         v20.8h, v22.8h, v23.8h        \n"
+      "add         v0.8h, v2.8h, v3.8h           \n"
+      "add         v21.8h, v20.8h, v24.8h        \n"  // a+b+i+j+c+k ...
+      "add         v1.8h, v0.8h, v4.8h           \n"
 
-      // 00+10 01+11 02+12 03+13
-      // 40+50 41+51 42+52 43+53
-      "uaddlp      v16.4h, v16.8b                \n"
-      "uaddlp      v17.4h, v17.8b                \n"
-      "uaddlp      v18.4h, v18.8b                \n"
-      "uaddlp      v19.4h, v19.8b                \n"
-
-      // 60+70 61+71 62+72 63+73
-      "uaddlp      v1.4h, v1.8b                  \n"
-      "uaddlp      v5.4h, v5.8b                  \n"
-
-      // combine source lines
-      "add         v16.4h, v16.4h, v18.4h        \n"
-      "add         v17.4h, v17.4h, v19.4h        \n"
-      "add         v2.4h, v1.4h, v5.4h           \n"
-
-      // dst_ptr[3] = (s[6] + s[7] + s[6+st] + s[7+st]) / 4
-      "uqrshrn     v2.8b, v2.8h, #2              \n"
-
-      // Shuffle 2,3 reg around so that 2 can be added to the
-      //  0,1 reg and 3 can be added to the 4,5 reg. This
-      //  requires expanding from u8 to u16 as the 0,1 and 4,5
-      //  registers are already expanded. Then do transposes
-      //  to get aligned.
-      // xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33
-
-      // combine source lines
-      "uaddl       v0.8h, v0.8b, v4.8b           \n"
-
-      // xx 20 xx 21 xx 22 xx 23
-      // xx 30 xx 31 xx 32 xx 33
-      "trn1        v1.8h, v0.8h, v0.8h           \n"
-      "trn2        v4.8h, v0.8h, v0.8h           \n"
-      "xtn         v0.4h, v1.4s                  \n"
-      "xtn         v4.4h, v4.4s                  \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-
-      // 0+1+2, 3+4+5
-      "add         v16.8h, v16.8h, v0.8h         \n"
-      "add         v17.8h, v17.8h, v4.8h         \n"
-      "prfm        pldl1keep, [%2, 448]          \n"
-
-      // Need to divide, but can't downshift as the the value
-      //  isn't a power of 2. So multiply by 65536 / n
-      //  and take the upper 16 bits.
-      "sqrdmulh    v0.8h, v16.8h, v30.8h         \n"
-      "sqrdmulh    v1.8h, v17.8h, v30.8h         \n"
-
-      // Align for table lookup, vtbl requires registers to
-      //  be adjacent
-
-      "tbl         v3.16b, {v0.16b, v1.16b, v2.16b}, v31.16b \n"
-
-      "st1         {v3.8b}, [%1], #8             \n"
-      "st1         {v3.s}[2], [%1], #4           \n"
+      "sqrdmulh    v21.8h, v21.8h, v30.8h        \n"  // v /= {6,6,4}
+      "sqrdmulh    v22.8h, v1.8h, v30.8h         \n"
+      "tbl         v21.16b, {v21.16b, v22.16b}, v31.16b \n"  // Narrow.
+      "st1         {v21.d}[0], [%[dst_ptr]], #8  \n"
+      "st1         {v21.s}[2], [%[dst_ptr]], #4  \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),         // %0
-        "+r"(dst_ptr),         // %1
-        "+r"(tmp_src_stride),  // %2
-        "+r"(dst_width)        // %3
-      : "r"(&kMult38_Div6),    // %4
-        "r"(&kShuf38_2)        // %5
-      : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18",
-        "v19", "v30", "v31", "memory", "cc");
+      : [src_ptr] "+r"(src_ptr),                         // %[src_ptr]
+        [dst_ptr] "+r"(dst_ptr),                         // %[dst_ptr]
+        [src_ptr1] "+r"(src_ptr1),                       // %[src_ptr1]
+        [width] "+r"(dst_width)                          // %[width]
+      : [div664] "r"(&kMult38_Div664),                   // %[div664]
+        [tblArray1] "r"(kScaleRowDown38_2_BoxIndices1),  // %[tblArray1]
+        [tblArray2] "r"(kScaleRowDown38_2_BoxIndices2),  // %[tblArray2]
+        [tblArray3] "r"(kScaleRowDown38_NarrowIndices)   // %[tblArray3]
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v20", "v21", "v22",
+        "v23", "v24", "v28", "v29", "v30", "v31");
 }
 
 void ScaleRowUp2_Linear_NEON(const uint8_t* src_ptr,
@@ -540,31 +498,38 @@
                              int dst_width) {
   const uint8_t* src_temp = src_ptr + 1;
   asm volatile(
-      "movi        v31.8b, #3                    \n"
+      "movi        v31.16b, #3                   \n"
 
-      "1:                                        \n"
-      "ldr         d0, [%0], #8                  \n"  // 01234567
-      "ldr         d1, [%1], #8                  \n"  // 12345678
+      "1:          \n"
+      "ldr         q0, [%0], #16                 \n"  // 0123456789abcdef
+      "ldr         q1, [%1], #16                 \n"  // 123456789abcdefg
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
 
       "ushll       v2.8h, v0.8b, #0              \n"  // 01234567 (16b)
       "ushll       v3.8h, v1.8b, #0              \n"  // 12345678 (16b)
+      "ushll2      v4.8h, v0.16b, #0             \n"  // 89abcdef (16b)
+      "ushll2      v5.8h, v1.16b, #0             \n"  // 9abcdefg (16b)
 
       "umlal       v2.8h, v1.8b, v31.8b          \n"  // 3*near+far (odd)
       "umlal       v3.8h, v0.8b, v31.8b          \n"  // 3*near+far (even)
+      "umlal2      v4.8h, v1.16b, v31.16b        \n"  // 3*near+far (odd)
+      "umlal2      v5.8h, v0.16b, v31.16b        \n"  // 3*near+far (even)
 
       "rshrn       v2.8b, v2.8h, #2              \n"  // 3/4*near+1/4*far (odd)
       "rshrn       v1.8b, v3.8h, #2              \n"  // 3/4*near+1/4*far (even)
+      "rshrn2      v2.16b, v4.8h, #2             \n"  // 3/4*near+1/4*far (odd)
+      "rshrn2      v1.16b, v5.8h, #2             \n"  // 3/4*near+1/4*far (even)
 
-      "st2         {v1.8b, v2.8b}, [%2], #16     \n"  // store
-      "subs        %w3, %w3, #16                 \n"  // 8 sample -> 16 sample
+      "st2         {v1.16b, v2.16b}, [%2], #32   \n"
+      "subs        %w3, %w3, #32                 \n"
       "b.gt        1b                            \n"
       : "+r"(src_ptr),   // %0
         "+r"(src_temp),  // %1
         "+r"(dst_ptr),   // %2
         "+r"(dst_width)  // %3
       :
-      : "memory", "cc", "v0", "v1", "v2", "v3", "v31"  // Clobber List
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5",
+        "v31"  // Clobber List
   );
 }
 
@@ -582,7 +547,7 @@
       "movi        v31.8b, #3                    \n"
       "movi        v30.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d0, [%0], #8                  \n"  // 01234567
       "ldr         d1, [%2], #8                  \n"  // 12345678
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -637,7 +602,7 @@
   asm volatile(
       "movi        v31.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%0], #16            \n"  // 01234567 (16b)
       "ld1         {v1.8h}, [%1], #16            \n"  // 12345678 (16b)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -674,7 +639,7 @@
   asm volatile(
       "movi        v31.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v2.8h}, [%0], #16            \n"  // 01234567 (16b)
       "ld1         {v3.8h}, [%2], #16            \n"  // 12345678 (16b)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -728,7 +693,7 @@
   asm volatile(
       "movi        v31.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%0], #16            \n"  // 01234567 (16b)
       "ld1         {v1.8h}, [%1], #16            \n"  // 12345678 (16b)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -774,7 +739,7 @@
       "movi        v31.4h, #3                    \n"
       "movi        v30.4s, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d0, [%0], #8                  \n"  // 0123 (16b)
       "ldr         d1, [%2], #8                  \n"  // 1234 (16b)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -828,7 +793,7 @@
   asm volatile(
       "movi        v31.8b, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d0, [%0], #8                  \n"  // 00112233 (1u1v)
       "ldr         d1, [%1], #8                  \n"  // 11223344 (1u1v)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -868,7 +833,7 @@
       "movi        v31.8b, #3                    \n"
       "movi        v30.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d0, [%0], #8                  \n"
       "ldr         d1, [%2], #8                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -923,7 +888,7 @@
   asm volatile(
       "movi        v31.8h, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h}, [%0], #16            \n"  // 01234567 (16b)
       "ld1         {v1.8h}, [%1], #16            \n"  // 12345678 (16b)
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -971,7 +936,7 @@
       "movi        v31.4h, #3                    \n"
       "movi        v30.4s, #3                    \n"
 
-      "1:                                        \n"
+      "1:          \n"
       "ldr         d0, [%0], #8                  \n"
       "ldr         d1, [%2], #8                  \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -1023,7 +988,7 @@
                       uint16_t* dst_ptr,
                       int src_width) {
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v1.8h, v2.8h}, [%1]          \n"  // load accumulator
       "ld1         {v0.16b}, [%0], #16           \n"  // load 16 bytes
       "uaddw2      v2.8h, v2.8h, v0.16b          \n"  // add
@@ -1040,15 +1005,12 @@
   );
 }
 
-// TODO(Yang Zhang): Investigate less load instructions for
-// the x/dx stepping
-#define LOAD2_DATA8_LANE(n)                      \
-  "lsr        %5, %3, #16                    \n" \
-  "add        %6, %1, %5                     \n" \
-  "add        %3, %3, %4                     \n" \
-  "ld2        {v4.b, v5.b}[" #n "], [%6]     \n"
+#define SCALE_FILTER_COLS_STEP_ADDR                         \
+  "lsr        %[tmp_offset], %x[x], #16                 \n" \
+  "add        %[tmp_ptr], %[src_ptr], %[tmp_offset]     \n" \
+  "add        %x[x], %x[x], %x[dx]                      \n"
 
-// The NEON version mimics this formula (from row_common.cc):
+// The Neon version mimics this formula (from scale_common.cc):
 // #define BLENDER(a, b, f) (uint8_t)((int)(a) +
 //    ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16))
 
@@ -1058,65 +1020,69 @@
                           int x,
                           int dx) {
   int dx_offset[4] = {0, 1, 2, 3};
-  int* tmp = dx_offset;
-  const uint8_t* src_tmp = src_ptr;
-  int64_t x64 = (int64_t)x;    // NOLINT
-  int64_t dx64 = (int64_t)dx;  // NOLINT
-  asm volatile (
-      "dup         v0.4s, %w3                    \n"  // x
-      "dup         v1.4s, %w4                    \n"  // dx
-      "ld1         {v2.4s}, [%5]                 \n"  // 0 1 2 3
+  int64_t tmp_offset;
+  uint8_t* tmp_ptr;
+  asm volatile(
+      "dup         v0.4s, %w[x]                  \n"
+      "dup         v1.4s, %w[dx]                 \n"
+      "ld1         {v2.4s}, [%[dx_offset]]       \n"  // 0 1 2 3
       "shl         v3.4s, v1.4s, #2              \n"  // 4 * dx
+      "shl         v22.4s, v1.4s, #3             \n"  // 8 * dx
+
       "mul         v1.4s, v1.4s, v2.4s           \n"
-    // x         , x + 1 * dx, x + 2 * dx, x + 3 * dx
+      // x         , x + 1 * dx, x + 2 * dx, x + 3 * dx
       "add         v1.4s, v1.4s, v0.4s           \n"
-    // x + 4 * dx, x + 5 * dx, x + 6 * dx, x + 7 * dx
+      // x + 4 * dx, x + 5 * dx, x + 6 * dx, x + 7 * dx
       "add         v2.4s, v1.4s, v3.4s           \n"
-      "shl         v0.4s, v3.4s, #1              \n"  // 8 * dx
-      "1:                                        \n"
-    LOAD2_DATA8_LANE(0)
-    LOAD2_DATA8_LANE(1)
-    LOAD2_DATA8_LANE(2)
-    LOAD2_DATA8_LANE(3)
-    LOAD2_DATA8_LANE(4)
-    LOAD2_DATA8_LANE(5)
-    LOAD2_DATA8_LANE(6)
-    LOAD2_DATA8_LANE(7)
-      "mov         v6.16b, v1.16b                \n"
-      "mov         v7.16b, v2.16b                \n"
-      "uzp1        v6.8h, v6.8h, v7.8h           \n"
-      "ushll       v4.8h, v4.8b, #0              \n"
-      "ushll       v5.8h, v5.8b, #0              \n"
+
+      "movi        v0.8h, #0                     \n"
+
+      // truncate to uint16_t
+      "trn1        v22.8h, v22.8h, v0.8h         \n"
+      "trn1        v20.8h, v1.8h, v0.8h          \n"
+      "trn1        v21.8h, v2.8h, v0.8h          \n"
+
+      "1:          \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ldr         h6, [%[tmp_ptr]]              \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[1], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[2], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[3], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[4], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[5], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[6], [%[tmp_ptr]]       \n" SCALE_FILTER_COLS_STEP_ADDR
+      "ld1         {v6.h}[7], [%[tmp_ptr]]       \n"
+
+      "subs        %w[width], %w[width], #8      \n"  // 8 processed per loop
+      "trn1        v4.16b, v6.16b, v0.16b        \n"
+      "trn2        v5.16b, v6.16b, v0.16b        \n"
+
       "ssubl       v16.4s, v5.4h, v4.4h          \n"
       "ssubl2      v17.4s, v5.8h, v4.8h          \n"
-      "ushll       v7.4s, v6.4h, #0              \n"
-      "ushll2      v6.4s, v6.8h, #0              \n"
-      "mul         v16.4s, v16.4s, v7.4s         \n"
-      "mul         v17.4s, v17.4s, v6.4s         \n"
+      "mul         v16.4s, v16.4s, v20.4s        \n"
+      "mul         v17.4s, v17.4s, v21.4s        \n"
       "rshrn       v6.4h, v16.4s, #16            \n"
       "rshrn2      v6.8h, v17.4s, #16            \n"
       "add         v4.8h, v4.8h, v6.8h           \n"
       "xtn         v4.8b, v4.8h                  \n"
 
-      "st1         {v4.8b}, [%0], #8             \n"  // store pixels
-      "add         v1.4s, v1.4s, v0.4s           \n"
-      "add         v2.4s, v2.4s, v0.4s           \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
+      "add         v20.8h, v20.8h, v22.8h        \n"
+      "add         v21.8h, v21.8h, v22.8h        \n"
+
+      "st1         {v4.8b}, [%[dst_ptr]], #8     \n"  // store pixels
       "b.gt        1b                            \n"
-  : "+r"(dst_ptr),          // %0
-    "+r"(src_ptr),          // %1
-    "+r"(dst_width),        // %2
-    "+r"(x64),              // %3
-    "+r"(dx64),             // %4
-    "+r"(tmp),              // %5
-    "+r"(src_tmp)           // %6
-  :
-  : "memory", "cc", "v0", "v1", "v2", "v3",
-    "v4", "v5", "v6", "v7", "v16", "v17"
-  );
+      : [src_ptr] "+r"(src_ptr),         // %[src_ptr]
+        [dst_ptr] "+r"(dst_ptr),         // %[dst_ptr]
+        [width] "+r"(dst_width),         // %[width]
+        [x] "+r"(x),                     // %[x]
+        [dx] "+r"(dx),                   // %[dx]
+        [tmp_offset] "=&r"(tmp_offset),  // %[tmp_offset]
+        [tmp_ptr] "=&r"(tmp_ptr)         // %[tmp_ptr]
+      : [dx_offset] "r"(dx_offset)       // %[dx_offset]
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v16", "v17",
+        "v20", "v21", "v22");
 }
 
-#undef LOAD2_DATA8_LANE
+#undef SCALE_FILTER_COLS_STEP_ADDR
 
 void ScaleARGBRowDown2_NEON(const uint8_t* src_ptr,
                             ptrdiff_t src_stride,
@@ -1124,20 +1090,19 @@
                             int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
-      // load 16 ARGB pixels with even pixels into q0/q2, odd into q1/q3
-      "ld4         {v0.4s,v1.4s,v2.4s,v3.4s}, [%0], #64 \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
-      "mov         v2.16b, v3.16b                \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "st2         {v1.4s,v2.4s}, [%1], #32      \n"  // store 8 odd pixels
+      "1:          \n"
+      "ld1         {v0.4s, v1.4s, v2.4s, v3.4s}, [%[src]], #64 \n"
+      "subs        %w[width], %w[width], #8      \n"
+      "prfm        pldl1keep, [%[src], 448]      \n"
+      "uzp2        v0.4s, v0.4s, v1.4s           \n"
+      "uzp2        v1.4s, v2.4s, v3.4s           \n"
+      "st1         {v0.4s, v1.4s}, [%[dst]], #32 \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),   // %0
-        "+r"(dst),       // %1
-        "+r"(dst_width)  // %2
+      : [src] "+r"(src_ptr),     // %[src]
+        [dst] "+r"(dst),         // %[dst]
+        [width] "+r"(dst_width)  // %[width]
       :
-      : "memory", "cc", "v0", "v1", "v2", "v3"  // Clobber List
-  );
+      : "memory", "cc", "v0", "v1", "v2", "v3");
 }
 
 void ScaleARGBRowDown2Linear_NEON(const uint8_t* src_argb,
@@ -1145,83 +1110,79 @@
                                   uint8_t* dst_argb,
                                   int dst_width) {
   (void)src_stride;
+  const uint8_t* src_argb1 = src_argb + 32;
   asm volatile(
-      "1:                                        \n"
-      // load 16 ARGB pixels with even pixels into q0/q2, odd into q1/q3
-      "ld4         {v0.4s,v1.4s,v2.4s,v3.4s}, [%0], #64 \n"
-      "subs        %w2, %w2, #8                  \n"  // 8 processed per loop
-
-      "urhadd      v0.16b, v0.16b, v1.16b        \n"  // rounding half add
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
+      "1:          \n"
+      "ld2         {v0.4s, v1.4s}, [%[src]]      \n"
+      "add         %[src], %[src], #64           \n"
+      "ld2         {v2.4s, v3.4s}, [%[src1]]     \n"
+      "add         %[src1], %[src1], #64         \n"
+      "urhadd      v0.16b, v0.16b, v1.16b        \n"
       "urhadd      v1.16b, v2.16b, v3.16b        \n"
-      "st2         {v0.4s,v1.4s}, [%1], #32      \n"  // store 8 pixels
+      "subs        %w[width], %w[width], #8      \n"
+      "st1         {v0.16b, v1.16b}, [%[dst]], #32 \n"
       "b.gt        1b                            \n"
-      : "+r"(src_argb),  // %0
-        "+r"(dst_argb),  // %1
-        "+r"(dst_width)  // %2
+      : [src] "+r"(src_argb),    // %[src]
+        [src1] "+r"(src_argb1),  // %[src1]
+        [dst] "+r"(dst_argb),    // %[dst]
+        [width] "+r"(dst_width)  // %[width]
       :
-      : "memory", "cc", "v0", "v1", "v2", "v3"  // Clobber List
-  );
+      : "memory", "cc", "v0", "v1", "v2", "v3");
 }
 
 void ScaleARGBRowDown2Box_NEON(const uint8_t* src_ptr,
                                ptrdiff_t src_stride,
                                uint8_t* dst,
                                int dst_width) {
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
   asm volatile(
-      // change the stride to row 2 pointer
-      "add         %1, %1, %0                    \n"
-      "1:                                        \n"
-      "ld4         {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n"  // load 16 ARGB
-      "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
-      "uaddlp      v0.8h, v0.16b                 \n"  // B 16 bytes -> 8 shorts.
-      "uaddlp      v1.8h, v1.16b                 \n"  // G 16 bytes -> 8 shorts.
-      "uaddlp      v2.8h, v2.16b                 \n"  // R 16 bytes -> 8 shorts.
-      "uaddlp      v3.8h, v3.16b                 \n"  // A 16 bytes -> 8 shorts.
-      "ld4         {v16.16b,v17.16b,v18.16b,v19.16b}, [%1], #64 \n"  // load 8
-      "uadalp      v0.8h, v16.16b                \n"  // B 16 bytes -> 8 shorts.
-      "uadalp      v1.8h, v17.16b                \n"  // G 16 bytes -> 8 shorts.
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "uadalp      v2.8h, v18.16b                \n"  // R 16 bytes -> 8 shorts.
-      "uadalp      v3.8h, v19.16b                \n"  // A 16 bytes -> 8 shorts.
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "rshrn       v0.8b, v0.8h, #2              \n"  // round and pack
+      "1:          \n"
+      "ld2         {v0.4s, v1.4s}, [%[src]], #32 \n"
+      "ld2         {v20.4s, v21.4s}, [%[src1]], #32 \n"
+      "uaddl       v2.8h, v0.8b, v1.8b           \n"
+      "uaddl2      v3.8h, v0.16b, v1.16b         \n"
+      "uaddl       v22.8h, v20.8b, v21.8b        \n"
+      "uaddl2      v23.8h, v20.16b, v21.16b      \n"
+      "add         v0.8h, v2.8h, v22.8h          \n"
+      "add         v1.8h, v3.8h, v23.8h          \n"
+      "rshrn       v0.8b, v0.8h, #2              \n"
       "rshrn       v1.8b, v1.8h, #2              \n"
-      "rshrn       v2.8b, v2.8h, #2              \n"
-      "rshrn       v3.8b, v3.8h, #2              \n"
-      "st4         {v0.8b,v1.8b,v2.8b,v3.8b}, [%2], #32 \n"
+      "subs        %w[width], %w[width], #4      \n"
+      "stp         d0, d1, [%[dst]], #16         \n"
       "b.gt        1b                            \n"
-      : "+r"(src_ptr),     // %0
-        "+r"(src_stride),  // %1
-        "+r"(dst),         // %2
-        "+r"(dst_width)    // %3
+      : [src] "+r"(src_ptr), [src1] "+r"(src_ptr1), [dst] "+r"(dst),
+        [width] "+r"(dst_width)
       :
-      : "memory", "cc", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v20", "v21", "v22", "v23");
 }
 
-// Reads 4 pixels at a time.
-// Alignment requirement: src_argb 4 byte aligned.
 void ScaleARGBRowDownEven_NEON(const uint8_t* src_argb,
                                ptrdiff_t src_stride,
                                int src_stepx,
                                uint8_t* dst_argb,
                                int dst_width) {
+  const uint8_t* src_argb1 = src_argb + src_stepx * 4;
+  const uint8_t* src_argb2 = src_argb + src_stepx * 8;
+  const uint8_t* src_argb3 = src_argb + src_stepx * 12;
+  int64_t i = 0;
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
-      "ld1         {v0.s}[0], [%0], %3           \n"
-      "ld1         {v0.s}[1], [%0], %3           \n"
-      "ld1         {v0.s}[2], [%0], %3           \n"
-      "ld1         {v0.s}[3], [%0], %3           \n"
-      "subs        %w2, %w2, #4                  \n"  // 4 pixels per loop.
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "st1         {v0.16b}, [%1], #16           \n"
+      "1:          \n"
+      "ldr         w10, [%[src], %[i]]           \n"
+      "ldr         w11, [%[src1], %[i]]          \n"
+      "ldr         w12, [%[src2], %[i]]          \n"
+      "ldr         w13, [%[src3], %[i]]          \n"
+      "add         %[i], %[i], %[step]           \n"
+      "subs        %w[width], %w[width], #4      \n"
+      "prfm        pldl1keep, [%[src], 448]      \n"
+      "stp         w10, w11, [%[dst]], #8        \n"
+      "stp         w12, w13, [%[dst]], #8        \n"
       "b.gt        1b                            \n"
-      : "+r"(src_argb),                // %0
-        "+r"(dst_argb),                // %1
-        "+r"(dst_width)                // %2
-      : "r"((int64_t)(src_stepx * 4))  // %3
-      : "memory", "cc", "v0");
+      : [src] "+r"(src_argb), [src1] "+r"(src_argb1), [src2] "+r"(src_argb2),
+        [src3] "+r"(src_argb3), [dst] "+r"(dst_argb), [width] "+r"(dst_width),
+        [i] "+r"(i)
+      : [step] "r"((int64_t)(src_stepx * 16))
+      : "memory", "cc", "w10", "w11", "w12", "w13");
 }
 
 // Reads 4 pixels at a time.
@@ -1235,7 +1196,7 @@
                                   int dst_width) {
   asm volatile(
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8b}, [%0], %4             \n"  // Read 4 2x2 -> 2x1
       "ld1         {v1.8b}, [%1], %4             \n"
       "ld1         {v2.8b}, [%0], %4             \n"
@@ -1249,26 +1210,24 @@
       "uaddl       v4.8h, v4.8b, v5.8b           \n"
       "uaddl       v6.8h, v6.8b, v7.8b           \n"
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "mov         v16.d[1], v0.d[1]             \n"  // ab_cd -> ac_bd
-      "mov         v0.d[1], v2.d[0]              \n"
-      "mov         v2.d[0], v16.d[1]             \n"
-      "mov         v16.d[1], v4.d[1]             \n"  // ef_gh -> eg_fh
-      "mov         v4.d[1], v6.d[0]              \n"
-      "mov         v6.d[0], v16.d[1]             \n"
+      "zip1        v1.2d, v0.2d, v2.2d           \n"
+      "zip2        v2.2d, v0.2d, v2.2d           \n"
+      "zip1        v5.2d, v4.2d, v6.2d           \n"
+      "zip2        v6.2d, v4.2d, v6.2d           \n"
       "prfm        pldl1keep, [%1, 448]          \n"
-      "add         v0.8h, v0.8h, v2.8h           \n"  // (a+b)_(c+d)
-      "add         v4.8h, v4.8h, v6.8h           \n"  // (e+f)_(g+h)
+      "add         v0.8h, v1.8h, v2.8h           \n"  // (a+b)_(c+d)
+      "add         v4.8h, v5.8h, v6.8h           \n"  // (e+f)_(g+h)
       "rshrn       v0.8b, v0.8h, #2              \n"  // first 2 pixels.
-      "rshrn2      v0.16b, v4.8h, #2             \n"  // next 2 pixels.
+      "rshrn       v1.8b, v4.8h, #2              \n"  // next 2 pixels.
       "subs        %w3, %w3, #4                  \n"  // 4 pixels per loop.
-      "st1         {v0.16b}, [%2], #16           \n"
+      "stp         d0, d1, [%2], #16             \n"
       "b.gt        1b                            \n"
       : "+r"(src_argb),                // %0
         "+r"(src_stride),              // %1
         "+r"(dst_argb),                // %2
         "+r"(dst_width)                // %3
       : "r"((int64_t)(src_stepx * 4))  // %4
-      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16");
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
 }
 
 // TODO(Yang Zhang): Investigate less load instructions for
@@ -1288,8 +1247,8 @@
   int64_t x64 = (int64_t)x;    // NOLINT
   int64_t dx64 = (int64_t)dx;  // NOLINT
   int64_t tmp64;
-  asm volatile(
-      "1:                                        \n"
+  asm volatile (
+      "1:          \n"
       // clang-format off
       LOAD1_DATA32_LANE(v0, 0)
       LOAD1_DATA32_LANE(v0, 1)
@@ -1317,13 +1276,14 @@
 
 #undef LOAD1_DATA32_LANE
 
-// TODO(Yang Zhang): Investigate less load instructions for
-// the x/dx stepping
-#define LOAD2_DATA32_LANE(vn1, vn2, n)                  \
-  "lsr        %5, %3, #16                           \n" \
-  "add        %6, %1, %5, lsl #2                    \n" \
-  "add        %3, %3, %4                            \n" \
-  "ld2        {" #vn1 ".s, " #vn2 ".s}[" #n "], [%6]  \n"
+static const uvec8 kScaleARGBFilterColsShuffleIndices = {
+    0, 0, 0, 0, 2, 2, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6,
+};
+
+#define SCALE_ARGB_FILTER_COLS_STEP_ADDR         \
+  "lsr        %5, %3, #16                    \n" \
+  "add        %6, %1, %5, lsl #2             \n" \
+  "add        %3, %3, %4                     \n"
 
 void ScaleARGBFilterCols_NEON(uint8_t* dst_argb,
                               const uint8_t* src_argb,
@@ -1331,64 +1291,130 @@
                               int x,
                               int dx) {
   int dx_offset[4] = {0, 1, 2, 3};
-  int* tmp = dx_offset;
+  int64_t tmp;
   const uint8_t* src_tmp = src_argb;
-  int64_t x64 = (int64_t)x;    // NOLINT
-  int64_t dx64 = (int64_t)dx;  // NOLINT
-  asm volatile (
-      "dup         v0.4s, %w3                    \n"  // x
-      "dup         v1.4s, %w4                    \n"  // dx
-      "ld1         {v2.4s}, [%5]                 \n"  // 0 1 2 3
-      "shl         v6.4s, v1.4s, #2              \n"  // 4 * dx
+  int64_t x64 = (int64_t)x;
+  int64_t dx64 = (int64_t)dx;
+  asm volatile(
+      "dup         v0.4s, %w3                    \n"
+      "dup         v1.4s, %w4                    \n"
+      "ld1         {v2.4s}, [%[kOffsets]]        \n"
+      "shl         v6.4s, v1.4s, #2              \n"
       "mul         v1.4s, v1.4s, v2.4s           \n"
-      "movi        v3.16b, #0x7f                 \n"  // 0x7F
-      "movi        v4.8h, #0x7f                  \n"  // 0x7F
-    // x         , x + 1 * dx, x + 2 * dx, x + 3 * dx
+      "movi        v3.16b, #0x7f                 \n"
+
       "add         v5.4s, v1.4s, v0.4s           \n"
-      "1:                                        \n"
-    // d0, d1: a
-    // d2, d3: b
-    LOAD2_DATA32_LANE(v0, v1, 0)
-    LOAD2_DATA32_LANE(v0, v1, 1)
-    LOAD2_DATA32_LANE(v0, v1, 2)
-    LOAD2_DATA32_LANE(v0, v1, 3)
-    "shrn       v2.4h, v5.4s, #9               \n"
-    "and        v2.8b, v2.8b, v4.8b            \n"
-    "dup        v16.8b, v2.b[0]                \n"
-    "dup        v17.8b, v2.b[2]                \n"
-    "dup        v18.8b, v2.b[4]                \n"
-    "dup        v19.8b, v2.b[6]                \n"
-    "ext        v2.8b, v16.8b, v17.8b, #4      \n"
-    "ext        v17.8b, v18.8b, v19.8b, #4     \n"
-    "ins        v2.d[1], v17.d[0]              \n"  // f
-    "eor        v7.16b, v2.16b, v3.16b         \n"  // 0x7f ^ f
-    "umull      v16.8h, v0.8b, v7.8b           \n"
-    "umull2     v17.8h, v0.16b, v7.16b         \n"
-    "umull      v18.8h, v1.8b, v2.8b           \n"
-    "umull2     v19.8h, v1.16b, v2.16b         \n"
-    "prfm       pldl1keep, [%1, 448]           \n"  // prefetch 7 lines ahead
-    "add        v16.8h, v16.8h, v18.8h         \n"
-    "add        v17.8h, v17.8h, v19.8h         \n"
-    "shrn       v0.8b, v16.8h, #7              \n"
-    "shrn2      v0.16b, v17.8h, #7             \n"
-    "st1     {v0.4s}, [%0], #16                \n"  // store pixels
-    "add     v5.4s, v5.4s, v6.4s               \n"
-    "subs    %w2, %w2, #4                      \n"  // 4 processed per loop
-    "b.gt       1b                             \n"
-  : "+r"(dst_argb),         // %0
-    "+r"(src_argb),         // %1
-    "+r"(dst_width),        // %2
-    "+r"(x64),              // %3
-    "+r"(dx64),             // %4
-    "+r"(tmp),              // %5
-    "+r"(src_tmp)           // %6
-  :
-  : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5",
-    "v6", "v7", "v16", "v17", "v18", "v19"
-  );
+      "ldr         q18, [%[kIndices]]            \n"
+
+      "1:          \n"  //
+      SCALE_ARGB_FILTER_COLS_STEP_ADDR
+      "ldr         d1, [%6]                      \n"  //
+      SCALE_ARGB_FILTER_COLS_STEP_ADDR
+      "ldr         d2, [%6]                      \n"
+      "shrn        v4.4h, v5.4s, #9              \n"  //
+      SCALE_ARGB_FILTER_COLS_STEP_ADDR
+      "ld1         {v1.d}[1], [%6]               \n"  //
+      SCALE_ARGB_FILTER_COLS_STEP_ADDR
+      "ld1         {v2.d}[1], [%6]               \n"
+
+      "subs        %w2, %w2, #4                  \n"  // 4 processed per loop
+      "and         v4.8b, v4.8b, v3.8b           \n"
+      "trn1        v0.4s, v1.4s, v2.4s           \n"
+      "tbl         v4.16b, {v4.16b}, v18.16b     \n"  // f
+      "trn2        v1.4s, v1.4s, v2.4s           \n"
+      "eor         v7.16b, v4.16b, v3.16b        \n"  // 0x7f ^ f
+
+      "umull       v16.8h, v1.8b, v4.8b          \n"
+      "umull2      v17.8h, v1.16b, v4.16b        \n"
+      "umlal       v16.8h, v0.8b, v7.8b          \n"
+      "umlal2      v17.8h, v0.16b, v7.16b        \n"
+
+      "prfm        pldl1keep, [%1, 448]          \n"  // prefetch 7 lines ahead
+      "shrn        v0.8b, v16.8h, #7             \n"
+      "shrn        v1.8b, v17.8h, #7             \n"
+      "add         v5.4s, v5.4s, v6.4s           \n"
+      "stp         d0, d1, [%0], #16             \n"  // store pixels
+      "b.gt        1b                            \n"
+      : "+r"(dst_argb),                                       // %0
+        "+r"(src_argb),                                       // %1
+        "+r"(dst_width),                                      // %2
+        "+r"(x64),                                            // %3
+        "+r"(dx64),                                           // %4
+        "=&r"(tmp),                                           // %5
+        "+r"(src_tmp)                                         // %6
+      : [kIndices] "r"(&kScaleARGBFilterColsShuffleIndices),  // %[kIndices]
+        [kOffsets] "r"(dx_offset)                             // %[kOffsets]
+      : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16",
+        "v17", "v18", "v19");
 }
 
-#undef LOAD2_DATA32_LANE
+#undef SCALE_ARGB_FILTER_COLS_STEP_ADDR
+
+void ScaleRowDown2_16_NEON(const uint16_t* src_ptr,
+                           ptrdiff_t src_stride,
+                           uint16_t* dst,
+                           int dst_width) {
+  (void)src_stride;
+  asm volatile(
+      "subs        %w[dst_width], %w[dst_width], #32 \n"
+      "b.lt        2f                            \n"
+
+      "1:          \n"
+      "ldp         q0, q1, [%[src_ptr]]          \n"
+      "ldp         q2, q3, [%[src_ptr], #32]     \n"
+      "ldp         q4, q5, [%[src_ptr], #64]     \n"
+      "ldp         q6, q7, [%[src_ptr], #96]     \n"
+      "add         %[src_ptr], %[src_ptr], #128  \n"
+      "uzp2        v0.8h, v0.8h, v1.8h           \n"
+      "uzp2        v1.8h, v2.8h, v3.8h           \n"
+      "uzp2        v2.8h, v4.8h, v5.8h           \n"
+      "uzp2        v3.8h, v6.8h, v7.8h           \n"
+      "subs        %w[dst_width], %w[dst_width], #32 \n"  // 32 elems per
+                                                          // iteration.
+      "stp         q0, q1, [%[dst_ptr]]          \n"
+      "stp         q2, q3, [%[dst_ptr], #32]     \n"
+      "add         %[dst_ptr], %[dst_ptr], #64   \n"
+      "b.ge        1b                            \n"
+
+      "2:          \n"
+      "adds        %w[dst_width], %w[dst_width], #32 \n"
+      "b.eq        99f                           \n"
+
+      "ldp         q0, q1, [%[src_ptr]]          \n"
+      "ldp         q2, q3, [%[src_ptr], #32]     \n"
+      "uzp2        v0.8h, v0.8h, v1.8h           \n"
+      "uzp2        v1.8h, v2.8h, v3.8h           \n"
+      "stp         q0, q1, [%[dst_ptr]]          \n"
+
+      "99:         \n"
+      : [src_ptr] "+r"(src_ptr),     // %[src_ptr]
+        [dst_ptr] "+r"(dst),         // %[dst_ptr]
+        [dst_width] "+r"(dst_width)  // %[dst_width]
+      :
+      : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7");
+}
+
+void ScaleRowDown2Linear_16_NEON(const uint16_t* src_ptr,
+                                 ptrdiff_t src_stride,
+                                 uint16_t* dst,
+                                 int dst_width) {
+  (void)src_stride;
+  asm volatile(
+      "1:          \n"
+      "ld2         {v0.8h, v1.8h}, [%[src_ptr]], #32 \n"
+      "ld2         {v2.8h, v3.8h}, [%[src_ptr]], #32 \n"
+      "subs        %w[dst_width], %w[dst_width], #16 \n"
+      "urhadd      v0.8h, v0.8h, v1.8h           \n"
+      "urhadd      v1.8h, v2.8h, v3.8h           \n"
+      "prfm        pldl1keep, [%[src_ptr], 448]  \n"
+      "stp         q0, q1, [%[dst_ptr]], #32     \n"
+      "b.gt        1b                            \n"
+      : [src_ptr] "+r"(src_ptr),     // %[src_ptr]
+        [dst_ptr] "+r"(dst),         // %[dst_ptr]
+        [dst_width] "+r"(dst_width)  // %[dst_width]
+      :
+      : "memory", "cc", "v0", "v1", "v2", "v3");
+}
 
 // Read 16x2 average down and write 8x1.
 void ScaleRowDown2Box_16_NEON(const uint16_t* src_ptr,
@@ -1398,7 +1424,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %0, %1, lsl #1            \n"  // ptr + stide * 2
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.8h, v1.8h}, [%0], #32     \n"  // load row 1 and post inc
       "ld1         {v2.8h, v3.8h}, [%1], #32     \n"  // load row 2 and post inc
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop
@@ -1417,59 +1443,7 @@
         "+r"(dst),         // %2
         "+r"(dst_width)    // %3
       :
-      : "v0", "v1", "v2", "v3"  // Clobber List
-  );
-}
-
-// Read 8x2 upsample with filtering and write 16x1.
-// Actually reads an extra pixel, so 9x2.
-void ScaleRowUp2_16_NEON(const uint16_t* src_ptr,
-                         ptrdiff_t src_stride,
-                         uint16_t* dst,
-                         int dst_width) {
-  asm volatile(
-      "add         %1, %0, %1, lsl #1            \n"  // ptr + stide * 2
-      "movi        v0.8h, #9                     \n"  // constants
-      "movi        v1.4s, #3                     \n"
-
-      "1:                                        \n"
-      "ld1         {v3.8h}, [%0], %4             \n"  // TL read first 8
-      "ld1         {v4.8h}, [%0], %5             \n"  // TR read 8 offset by 1
-      "ld1         {v5.8h}, [%1], %4             \n"  // BL read 8 from next row
-      "ld1         {v6.8h}, [%1], %5             \n"  // BR offset by 1
-      "subs        %w3, %w3, #16                 \n"  // 16 dst pixels per loop
-      "umull       v16.4s, v3.4h, v0.4h          \n"
-      "umull2      v7.4s, v3.8h, v0.8h           \n"
-      "umull       v18.4s, v4.4h, v0.4h          \n"
-      "umull2      v17.4s, v4.8h, v0.8h          \n"
-      "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
-      "uaddw       v16.4s, v16.4s, v6.4h         \n"
-      "uaddl2      v19.4s, v6.8h, v3.8h          \n"
-      "uaddl       v3.4s, v6.4h, v3.4h           \n"
-      "uaddw2      v6.4s, v7.4s, v6.8h           \n"
-      "uaddl2      v7.4s, v5.8h, v4.8h           \n"
-      "uaddl       v4.4s, v5.4h, v4.4h           \n"
-      "uaddw       v18.4s, v18.4s, v5.4h         \n"
-      "prfm        pldl1keep, [%1, 448]          \n"
-      "mla         v16.4s, v4.4s, v1.4s          \n"
-      "mla         v18.4s, v3.4s, v1.4s          \n"
-      "mla         v6.4s, v7.4s, v1.4s           \n"
-      "uaddw2      v4.4s, v17.4s, v5.8h          \n"
-      "uqrshrn     v16.4h,  v16.4s, #4           \n"
-      "mla         v4.4s, v19.4s, v1.4s          \n"
-      "uqrshrn2    v16.8h, v6.4s, #4             \n"
-      "uqrshrn     v17.4h, v18.4s, #4            \n"
-      "uqrshrn2    v17.8h, v4.4s, #4             \n"
-      "st2         {v16.8h-v17.8h}, [%2], #32    \n"
-      "b.gt        1b                            \n"
-      : "+r"(src_ptr),     // %0
-        "+r"(src_stride),  // %1
-        "+r"(dst),         // %2
-        "+r"(dst_width)    // %3
-      : "r"(2LL),          // %4
-        "r"(14LL)          // %5
-      : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18",
-        "v19"  // Clobber List
+      : "memory", "cc", "v0", "v1", "v2", "v3"  // Clobber List
   );
 }
 
@@ -1479,7 +1453,7 @@
                           int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.8h,v1.8h}, [%0], #32      \n"  // load 16 UV
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "prfm        pldl1keep, [%0, 448]          \n"  // prefetch 7 lines ahead
@@ -1498,7 +1472,7 @@
                                 int dst_width) {
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.8h,v1.8h}, [%0], #32      \n"  // load 16 UV
       "subs        %w2, %w2, #8                  \n"  // 8 processed per loop.
       "urhadd      v0.16b, v0.16b, v1.16b        \n"  // rounding half add
@@ -1519,7 +1493,7 @@
   asm volatile(
       // change the stride to row 2 pointer
       "add         %1, %1, %0                    \n"
-      "1:                                        \n"
+      "1:          \n"
       "ld2         {v0.16b,v1.16b}, [%0], #32    \n"  // load 16 UV
       "subs        %w3, %w3, #8                  \n"  // 8 processed per loop.
       "uaddlp      v0.8h, v0.16b                 \n"  // U 16 bytes -> 8 shorts.
@@ -1552,7 +1526,7 @@
   const uint8_t* src3_ptr = src_ptr + src_stepx * 6;
   (void)src_stride;
   asm volatile(
-      "1:                                        \n"
+      "1:          \n"
       "ld1         {v0.h}[0], [%0], %6           \n"
       "ld1         {v1.h}[0], [%1], %6           \n"
       "ld1         {v2.h}[0], [%2], %6           \n"
diff --git a/source/scale_rgb.cc b/source/scale_rgb.cc
index 8db59b5..5e69fe3 100644
--- a/source/scale_rgb.cc
+++ b/source/scale_rgb.cc
@@ -11,6 +11,9 @@
 #include "libyuv/scale.h" /* For FilterMode */
 
 #include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "libyuv/convert_argb.h"
@@ -38,18 +41,31 @@
              int dst_height,
              enum FilterMode filtering) {
   int r;
-  uint8_t* src_argb =
-      (uint8_t*)malloc(src_width * src_height * 4 + dst_width * dst_height * 4);
-  uint8_t* dst_argb = src_argb + src_width * src_height * 4;
-
-  if (!src_argb) {
-    return 1;
+  if (!src_rgb || !dst_rgb || src_width <= 0 || src_width > INT_MAX / 4 ||
+      src_height == 0 || dst_width <= 0 || dst_width > INT_MAX / 4 ||
+      dst_height <= 0) {
+    return -1;
   }
+  const int abs_src_height = (src_height < 0) ? -src_height : src_height;
+  const uint64_t src_argb_size = (uint64_t)src_width * abs_src_height * 4;
+  const uint64_t dst_argb_size = (uint64_t)dst_width * dst_height * 4;
+  if (src_argb_size > (UINT64_MAX - dst_argb_size)) {
+    return -1;  // Invalid size.
+  }
+  const uint64_t argb_size = src_argb_size + dst_argb_size;
+  if (argb_size > SIZE_MAX) {
+    return -1;  // Invalid size.
+  }
+  uint8_t* src_argb = (uint8_t*)malloc((size_t)argb_size);
+  if (!src_argb) {
+    return 1;  // Out of memory runtime error.
+  }
+  uint8_t* dst_argb = src_argb + (size_t)src_argb_size;
 
   r = RGB24ToARGB(src_rgb, src_stride_rgb, src_argb, src_width * 4, src_width,
                   src_height);
   if (!r) {
-    r = ARGBScale(src_argb, src_width * 4, src_width, src_height, dst_argb,
+    r = ARGBScale(src_argb, src_width * 4, src_width, abs_src_height, dst_argb,
                   dst_width * 4, dst_width, dst_height, filtering);
     if (!r) {
       r = ARGBToRGB24(dst_argb, dst_width * 4, dst_rgb, dst_stride_rgb,
diff --git a/source/scale_rvv.cc b/source/scale_rvv.cc
index de037e4..877ccdf 100644
--- a/source/scale_rvv.cc
+++ b/source/scale_rvv.cc
@@ -28,6 +28,55 @@
 extern "C" {
 #endif
 
+#ifdef HAS_SCALEARGBFILTERCOLS_RVV
+void ScaleARGBFilterCols_RVV(uint8_t* dst_argb,
+                             const uint8_t* src_argb,
+                             int dst_width,
+                             int x,
+                             int dx) {
+  assert(x >= 0);
+
+  size_t vl = __riscv_vsetvl_e32m4(dst_width);
+  vuint32m4_t vx = __riscv_vmv_v_x_u32m4(x, vl);
+  vx = __riscv_vmacc_vx_u32m4(vx, dx, __riscv_vid_v_u32m4(vl), vl);
+  do {
+    vuint32m4_t v0_argb, v1_argb;
+    vuint32m4_t v_xf0_u32, v_xf1_u32;
+    vuint8m4_t v0_argb_u8, v1_argb_u8, v_xf0_u8, v_xf1_u8;
+    vuint16m8_t _v0_argb_u16, v_row_u16;
+    // idx is x >> 16
+    vuint32m4_t v_xi_bindex = __riscv_vsrl_vx_u32m4(vx, 14, vl);
+    v_xi_bindex = __riscv_vand_vx_u32m4(v_xi_bindex, ~3u, vl);
+    // Read Packed ARGB w/ byte index.
+    __riscv_vluxseg2ei32_v_u32m4(&v0_argb, &v1_argb, (const uint32_t*)src_argb,
+                                 v_xi_bindex, vl);
+    // xf = (x >> 9) & 0x7f;
+    v_xf0_u32 = __riscv_vsrl_vx_u32m4(vx, 9, vl);
+    v_xf0_u32 = __riscv_vand_vx_u32m4(v_xf0_u32, 0x7f, vl);
+    vx = __riscv_vadd_vx_u32m4(vx, vl * dx, vl);
+    // duplicate v_xf0_u32[i] from {0,0,0,f[i]} to {f[i],f[i],f[i],f[i]}
+    v_xf0_u32 = __riscv_vmul_vx_u32m4(v_xf0_u32, 0x01010101, vl);
+    // TODO(fbarchard): Replace 0x7f ^ f with 128-f.  bug=607.
+    v_xf1_u32 = __riscv_vxor_vx_u32m4(v_xf0_u32, 0x7f7f7f7f, vl);
+
+    v0_argb_u8 = __riscv_vreinterpret_v_u32m4_u8m4(v0_argb);
+    v1_argb_u8 = __riscv_vreinterpret_v_u32m4_u8m4(v1_argb);
+    v_xf0_u8 = __riscv_vreinterpret_v_u32m4_u8m4(v_xf0_u32);
+    v_xf1_u8 = __riscv_vreinterpret_v_u32m4_u8m4(v_xf1_u32);
+    // ((a) * (0x7f ^ f) + (b)*f) >> 7
+    _v0_argb_u16 = __riscv_vwmulu_vv_u16m8(v0_argb_u8, v_xf1_u8, 4 * vl);
+    v_row_u16 =
+        __riscv_vwmaccu_vv_u16m8(_v0_argb_u16, v1_argb_u8, v_xf0_u8, 4 * vl);
+
+    __riscv_vse8_v_u8m4(dst_argb, __riscv_vnsrl_wx_u8m4(v_row_u16, 7, 4 * vl),
+                        4 * vl);
+    dst_width -= vl;
+    dst_argb += 4 * vl;
+    vl = __riscv_vsetvl_e32m4(dst_width);
+  } while (dst_width > 0);
+}
+#endif
+
 #ifdef HAS_SCALEADDROW_RVV
 void ScaleAddRow_RVV(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width) {
   size_t w = (size_t)src_width;
@@ -46,6 +95,7 @@
 #endif
 
 #ifdef HAS_SCALEARGBROWDOWN2_RVV
+// TODO: Reimplement similar to linear with vlseg2 so u64 is not required
 void ScaleARGBRowDown2_RVV(const uint8_t* src_argb,
                            ptrdiff_t src_stride,
                            uint8_t* dst_argb,
@@ -67,6 +117,30 @@
 #endif
 
 #ifdef HAS_SCALEARGBROWDOWN2LINEAR_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleARGBRowDown2Linear_RVV(const uint8_t* src_argb,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst_argb,
+                                 int dst_width) {
+  (void)src_stride;
+  size_t w = (size_t)dst_width;
+  const uint32_t* src = (const uint32_t*)(src_argb);
+  do {
+    size_t vl = __riscv_vsetvl_e32m4(w);
+    vuint32m4x2_t v_src = __riscv_vlseg2e32_v_u32m4x2(src, vl);
+    vuint32m4_t v_even_32 = __riscv_vget_v_u32m4x2_u32m4(v_src, 0);
+    vuint32m4_t v_odd_32 = __riscv_vget_v_u32m4x2_u32m4(v_src, 1);
+    vuint8m4_t v_even = __riscv_vreinterpret_v_u32m4_u8m4(v_even_32);
+    vuint8m4_t v_odd = __riscv_vreinterpret_v_u32m4_u8m4(v_odd_32);
+    vuint8m4_t v_dst =
+        __riscv_vaaddu_vv_u8m4(v_even, v_odd, __RISCV_VXRM_RNU, vl * 4);
+    __riscv_vse8_v_u8m4(dst_argb, v_dst, vl * 4);
+    w -= vl;
+    src += vl * 2;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void ScaleARGBRowDown2Linear_RVV(const uint8_t* src_argb,
                                  ptrdiff_t src_stride,
                                  uint8_t* dst_argb,
@@ -93,8 +167,45 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEARGBROWDOWN2BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleARGBRowDown2Box_RVV(const uint8_t* src_argb,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_argb,
+                              int dst_width) {
+  size_t w = (size_t)dst_width;
+  const uint32_t* src0 = (const uint32_t*)(src_argb);
+  const uint32_t* src1 = (const uint32_t*)(src_argb + src_stride);
+  do {
+    size_t vl = __riscv_vsetvl_e32m4(w);
+    vuint32m4x2_t v_src0 = __riscv_vlseg2e32_v_u32m4x2(src0, vl);
+    vuint32m4x2_t v_src1 = __riscv_vlseg2e32_v_u32m4x2(src1, vl);
+    vuint32m4_t v_row0_even_32 = __riscv_vget_v_u32m4x2_u32m4(v_src0, 0);
+    vuint32m4_t v_row0_odd_32 = __riscv_vget_v_u32m4x2_u32m4(v_src0, 1);
+    vuint32m4_t v_row1_even_32 = __riscv_vget_v_u32m4x2_u32m4(v_src1, 0);
+    vuint32m4_t v_row1_odd_32 = __riscv_vget_v_u32m4x2_u32m4(v_src1, 1);
+    vuint8m4_t v_row0_even = __riscv_vreinterpret_v_u32m4_u8m4(v_row0_even_32);
+    vuint8m4_t v_row0_odd = __riscv_vreinterpret_v_u32m4_u8m4(v_row0_odd_32);
+    vuint8m4_t v_row1_even = __riscv_vreinterpret_v_u32m4_u8m4(v_row1_even_32);
+    vuint8m4_t v_row1_odd = __riscv_vreinterpret_v_u32m4_u8m4(v_row1_odd_32);
+    vuint16m8_t v_row0_sum =
+        __riscv_vwaddu_vv_u16m8(v_row0_even, v_row0_odd, vl * 4);
+    vuint16m8_t v_row1_sum =
+        __riscv_vwaddu_vv_u16m8(v_row1_even, v_row1_odd, vl * 4);
+    vuint16m8_t v_dst_16 =
+        __riscv_vadd_vv_u16m8(v_row0_sum, v_row1_sum, vl * 4);
+    vuint8m4_t v_dst =
+        __riscv_vnclipu_wx_u8m4(v_dst_16, 2, __RISCV_VXRM_RNU, vl * 4);
+    __riscv_vse8_v_u8m4(dst_argb, v_dst, vl * 4);
+    w -= vl;
+    src0 += vl * 2;
+    src1 += vl * 2;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void ScaleARGBRowDown2Box_RVV(const uint8_t* src_argb,
                               ptrdiff_t src_stride,
                               uint8_t* dst_argb,
@@ -129,6 +240,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEARGBROWDOWNEVEN_RVV
 void ScaleARGBRowDownEven_RVV(const uint8_t* src_argb,
@@ -152,6 +264,43 @@
 #endif
 
 #ifdef HAS_SCALEARGBROWDOWNEVENBOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleARGBRowDownEvenBox_RVV(const uint8_t* src_argb,
+                                 ptrdiff_t src_stride,
+                                 int src_stepx,
+                                 uint8_t* dst_argb,
+                                 int dst_width) {
+  size_t w = (size_t)dst_width;
+  const uint32_t* src0 = (const uint32_t*)(src_argb);
+  const uint32_t* src1 = (const uint32_t*)(src_argb + src_stride);
+  const int stride_byte = src_stepx * 4;
+  do {
+    size_t vl = __riscv_vsetvl_e32m4(w);
+    vuint32m4x2_t v_src0 = __riscv_vlsseg2e32_v_u32m4x2(src0, stride_byte, vl);
+    vuint32m4x2_t v_src1 = __riscv_vlsseg2e32_v_u32m4x2(src1, stride_byte, vl);
+    vuint32m4_t v_row0_low_32 = __riscv_vget_v_u32m4x2_u32m4(v_src0, 0);
+    vuint32m4_t v_row0_high_32 = __riscv_vget_v_u32m4x2_u32m4(v_src0, 1);
+    vuint32m4_t v_row1_low_32 = __riscv_vget_v_u32m4x2_u32m4(v_src1, 0);
+    vuint32m4_t v_row1_high_32 = __riscv_vget_v_u32m4x2_u32m4(v_src1, 1);
+    vuint8m4_t v_row0_low = __riscv_vreinterpret_v_u32m4_u8m4(v_row0_low_32);
+    vuint8m4_t v_row0_high = __riscv_vreinterpret_v_u32m4_u8m4(v_row0_high_32);
+    vuint8m4_t v_row1_low = __riscv_vreinterpret_v_u32m4_u8m4(v_row1_low_32);
+    vuint8m4_t v_row1_high = __riscv_vreinterpret_v_u32m4_u8m4(v_row1_high_32);
+    vuint16m8_t v_row0_sum =
+        __riscv_vwaddu_vv_u16m8(v_row0_low, v_row0_high, vl * 4);
+    vuint16m8_t v_row1_sum =
+        __riscv_vwaddu_vv_u16m8(v_row1_low, v_row1_high, vl * 4);
+    vuint16m8_t v_sum = __riscv_vadd_vv_u16m8(v_row0_sum, v_row1_sum, vl * 4);
+    vuint8m4_t v_dst =
+        __riscv_vnclipu_wx_u8m4(v_sum, 2, __RISCV_VXRM_RNU, vl * 4);
+    __riscv_vse8_v_u8m4(dst_argb, v_dst, vl * 4);
+    w -= vl;
+    src0 += vl * src_stepx;
+    src1 += vl * src_stepx;
+    dst_argb += vl * 4;
+  } while (w > 0);
+}
+#else
 void ScaleARGBRowDownEvenBox_RVV(const uint8_t* src_argb,
                                  ptrdiff_t src_stride,
                                  int src_stepx,
@@ -190,6 +339,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN2_RVV
 void ScaleRowDown2_RVV(const uint8_t* src_ptr,
@@ -212,6 +362,26 @@
 #endif
 
 #ifdef HAS_SCALEROWDOWN2LINEAR_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleRowDown2Linear_RVV(const uint8_t* src_ptr,
+                             ptrdiff_t src_stride,
+                             uint8_t* dst,
+                             int dst_width) {
+  size_t w = (size_t)dst_width;
+  (void)src_stride;
+  do {
+    size_t vl = __riscv_vsetvl_e8m4(w);
+    vuint8m4x2_t v_src = __riscv_vlseg2e8_v_u8m4x2(src_ptr, vl);
+    vuint8m4_t v_s0 = __riscv_vget_v_u8m4x2_u8m4(v_src, 0);
+    vuint8m4_t v_s1 = __riscv_vget_v_u8m4x2_u8m4(v_src, 1);
+    vuint8m4_t v_dst = __riscv_vaaddu_vv_u8m4(v_s0, v_s1, __RISCV_VXRM_RNU, vl);
+    __riscv_vse8_v_u8m4(dst, v_dst, vl);
+    w -= vl;
+    src_ptr += 2 * vl;
+    dst += vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown2Linear_RVV(const uint8_t* src_ptr,
                              ptrdiff_t src_stride,
                              uint8_t* dst,
@@ -234,8 +404,38 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN2BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleRowDown2Box_RVV(const uint8_t* src_ptr,
+                          ptrdiff_t src_stride,
+                          uint8_t* dst,
+                          int dst_width) {
+  const uint8_t* s = src_ptr;
+  const uint8_t* t = src_ptr + src_stride;
+  size_t w = (size_t)dst_width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m4(w);
+    vuint8m4x2_t v_s = __riscv_vlseg2e8_v_u8m4x2(s, vl);
+    vuint8m4x2_t v_t = __riscv_vlseg2e8_v_u8m4x2(t, vl);
+    vuint8m4_t v_s0 = __riscv_vget_v_u8m4x2_u8m4(v_s, 0);
+    vuint8m4_t v_s1 = __riscv_vget_v_u8m4x2_u8m4(v_s, 1);
+    vuint8m4_t v_t0 = __riscv_vget_v_u8m4x2_u8m4(v_t, 0);
+    vuint8m4_t v_t1 = __riscv_vget_v_u8m4x2_u8m4(v_t, 1);
+    vuint16m8_t v_s01 = __riscv_vwaddu_vv_u16m8(v_s0, v_s1, vl);
+    vuint16m8_t v_t01 = __riscv_vwaddu_vv_u16m8(v_t0, v_t1, vl);
+    vuint16m8_t v_st01 = __riscv_vadd_vv_u16m8(v_s01, v_t01, vl);
+    // Use round-to-nearest-up mode for vnclip
+    vuint8m4_t v_dst = __riscv_vnclipu_wx_u8m4(v_st01, 2, __RISCV_VXRM_RNU, vl);
+    __riscv_vse8_v_u8m4(dst, v_dst, vl);
+    w -= vl;
+    s += 2 * vl;
+    t += 2 * vl;
+    dst += vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown2Box_RVV(const uint8_t* src_ptr,
                           ptrdiff_t src_stride,
                           uint8_t* dst,
@@ -266,8 +466,27 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN4_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowDown4_RVV(const uint8_t* src_ptr,
+                       ptrdiff_t src_stride,
+                       uint8_t* dst_ptr,
+                       int dst_width) {
+  size_t w = (size_t)dst_width;
+  (void)src_stride;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_s = __riscv_vlseg4e8_v_u8m2x4(src_ptr, vl);
+    vuint8m2_t v_s2 = __riscv_vget_v_u8m2x4_u8m2(v_s, 2);
+    __riscv_vse8_v_u8m2(dst_ptr, v_s2, vl);
+    w -= vl;
+    src_ptr += (4 * vl);
+    dst_ptr += vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown4_RVV(const uint8_t* src_ptr,
                        ptrdiff_t src_stride,
                        uint8_t* dst_ptr,
@@ -285,8 +504,70 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN4BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleRowDown4Box_RVV(const uint8_t* src_ptr,
+                          ptrdiff_t src_stride,
+                          uint8_t* dst_ptr,
+                          int dst_width) {
+  const uint8_t* src_ptr1 = src_ptr + src_stride;
+  const uint8_t* src_ptr2 = src_ptr + src_stride * 2;
+  const uint8_t* src_ptr3 = src_ptr + src_stride * 3;
+  size_t w = (size_t)dst_width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_s = __riscv_vlseg4e8_v_u8m2x4(src_ptr, vl);
+    vuint8m2_t v_s0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 0);
+    vuint8m2_t v_s1 = __riscv_vget_v_u8m2x4_u8m2(v_s, 1);
+    vuint8m2_t v_s2 = __riscv_vget_v_u8m2x4_u8m2(v_s, 2);
+    vuint8m2_t v_s3 = __riscv_vget_v_u8m2x4_u8m2(v_s, 3);
+    vuint16m4_t v_s01 = __riscv_vwaddu_vv_u16m4(v_s0, v_s1, vl);
+    vuint8m2x4_t v_t = __riscv_vlseg4e8_v_u8m2x4(src_ptr1, vl);
+    vuint8m2_t v_t0 = __riscv_vget_v_u8m2x4_u8m2(v_t, 0);
+    vuint8m2_t v_t1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 1);
+    vuint8m2_t v_t2 = __riscv_vget_v_u8m2x4_u8m2(v_t, 2);
+    vuint8m2_t v_t3 = __riscv_vget_v_u8m2x4_u8m2(v_t, 3);
+    vuint16m4_t v_t01 = __riscv_vwaddu_vv_u16m4(v_t0, v_t1, vl);
+    vuint8m2x4_t v_u = __riscv_vlseg4e8_v_u8m2x4(src_ptr2, vl);
+    vuint8m2_t v_u0 = __riscv_vget_v_u8m2x4_u8m2(v_u, 0);
+    vuint8m2_t v_u1 = __riscv_vget_v_u8m2x4_u8m2(v_u, 1);
+    vuint8m2_t v_u2 = __riscv_vget_v_u8m2x4_u8m2(v_u, 2);
+    vuint8m2_t v_u3 = __riscv_vget_v_u8m2x4_u8m2(v_u, 3);
+    vuint16m4_t v_u01 = __riscv_vwaddu_vv_u16m4(v_u0, v_u1, vl);
+    vuint16m4_t v_u23 = __riscv_vwaddu_vv_u16m4(v_u2, v_u3, vl);
+    vuint16m4_t v_s23 = __riscv_vwaddu_vv_u16m4(v_s2, v_s3, vl);
+    vuint16m4_t v_t23 = __riscv_vwaddu_vv_u16m4(v_t2, v_t3, vl);
+    vuint16m4_t v_st01 = __riscv_vadd_vv_u16m4(v_s01, v_t01, vl);
+    vuint16m4_t v_st23 = __riscv_vadd_vv_u16m4(v_s23, v_t23, vl);
+    vuint8m2x4_t v_v = __riscv_vlseg4e8_v_u8m2x4(src_ptr3, vl);
+    vuint8m2_t v_v0 = __riscv_vget_v_u8m2x4_u8m2(v_v, 0);
+    vuint8m2_t v_v1 = __riscv_vget_v_u8m2x4_u8m2(v_v, 1);
+    vuint8m2_t v_v2 = __riscv_vget_v_u8m2x4_u8m2(v_v, 2);
+    vuint8m2_t v_v3 = __riscv_vget_v_u8m2x4_u8m2(v_v, 3);
+
+    vuint16m4_t v_v01 = __riscv_vwaddu_vv_u16m4(v_v0, v_v1, vl);
+    vuint16m4_t v_v23 = __riscv_vwaddu_vv_u16m4(v_v2, v_v3, vl);
+
+    vuint16m4_t v_uv01 = __riscv_vadd_vv_u16m4(v_u01, v_v01, vl);
+    vuint16m4_t v_uv23 = __riscv_vadd_vv_u16m4(v_u23, v_v23, vl);
+
+    vuint16m4_t v_st0123 = __riscv_vadd_vv_u16m4(v_st01, v_st23, vl);
+    vuint16m4_t v_uv0123 = __riscv_vadd_vv_u16m4(v_uv01, v_uv23, vl);
+    vuint16m4_t v_stuv0123 = __riscv_vadd_vv_u16m4(v_st0123, v_uv0123, vl);
+    vuint8m2_t v_dst =
+        __riscv_vnclipu_wx_u8m2(v_stuv0123, 4, __RISCV_VXRM_RNU, vl);
+    __riscv_vse8_v_u8m2(dst_ptr, v_dst, vl);
+    w -= vl;
+    src_ptr += 4 * vl;
+    src_ptr1 += 4 * vl;
+    src_ptr2 += 4 * vl;
+    src_ptr3 += 4 * vl;
+    dst_ptr += vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown4Box_RVV(const uint8_t* src_ptr,
                           ptrdiff_t src_stride,
                           uint8_t* dst_ptr,
@@ -348,8 +629,29 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN34_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowDown34_RVV(const uint8_t* src_ptr,
+                        ptrdiff_t src_stride,
+                        uint8_t* dst_ptr,
+                        int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_src = __riscv_vlseg4e8_v_u8m2x4(src_ptr, vl);
+    vuint8m2_t v_0 = __riscv_vget_v_u8m2x4_u8m2(v_src, 0);
+    vuint8m2_t v_1 = __riscv_vget_v_u8m2x4_u8m2(v_src, 1);
+    vuint8m2_t v_3 = __riscv_vget_v_u8m2x4_u8m2(v_src, 3);
+    vuint8m2x3_t v_dst = __riscv_vcreate_v_u8m2x3(v_0, v_1, v_3);
+    __riscv_vsseg3e8_v_u8m2x3(dst_ptr, v_dst, vl);
+    w -= vl;
+    src_ptr += 4 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown34_RVV(const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
                         uint8_t* dst_ptr,
@@ -366,8 +668,77 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN34_0_BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleRowDown34_0_Box_RVV(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_ptr,
+                              int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  const uint8_t* s = src_ptr;
+  const uint8_t* t = src_ptr + src_stride;
+  do {
+    vuint16m4_t v_t0_u16, v_t1_u16, v_t2_u16, v_t3_u16;
+    vuint8m2_t v_u0, v_u1, v_u2, v_u3;
+    vuint16m4_t v_u1_u16;
+    vuint8m2_t v_a0, v_a1, v_a2;
+    vuint8m2x3_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_s = __riscv_vlseg4e8_v_u8m2x4(s, vl);
+    vuint8m2_t v_s0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 0);
+    vuint8m2_t v_s1 = __riscv_vget_v_u8m2x4_u8m2(v_s, 1);
+    vuint8m2_t v_s2 = __riscv_vget_v_u8m2x4_u8m2(v_s, 2);
+    vuint8m2_t v_s3 = __riscv_vget_v_u8m2x4_u8m2(v_s, 3);
+
+    if (src_stride == 0) {
+      v_t0_u16 = __riscv_vwaddu_vx_u16m4(v_s0, 2, vl);
+      v_t1_u16 = __riscv_vwaddu_vx_u16m4(v_s1, 2, vl);
+      v_t2_u16 = __riscv_vwaddu_vx_u16m4(v_s2, 2, vl);
+      v_t3_u16 = __riscv_vwaddu_vx_u16m4(v_s3, 2, vl);
+    } else {
+      vuint8m2x4_t v_t = __riscv_vlseg4e8_v_u8m2x4(t, vl);
+      vuint8m2_t v_t0 = __riscv_vget_v_u8m2x4_u8m2(v_t, 0);
+      vuint8m2_t v_t1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 1);
+      vuint8m2_t v_t2 = __riscv_vget_v_u8m2x4_u8m2(v_t, 2);
+      vuint8m2_t v_t3 = __riscv_vget_v_u8m2x4_u8m2(v_t, 3);
+      v_t0_u16 = __riscv_vwaddu_vx_u16m4(v_t0, 0, vl);
+      v_t1_u16 = __riscv_vwaddu_vx_u16m4(v_t1, 0, vl);
+      v_t2_u16 = __riscv_vwaddu_vx_u16m4(v_t2, 0, vl);
+      v_t3_u16 = __riscv_vwaddu_vx_u16m4(v_t3, 0, vl);
+      t += 4 * vl;
+    }
+
+    v_t0_u16 = __riscv_vwmaccu_vx_u16m4(v_t0_u16, 3, v_s0, vl);
+    v_t1_u16 = __riscv_vwmaccu_vx_u16m4(v_t1_u16, 3, v_s1, vl);
+    v_t2_u16 = __riscv_vwmaccu_vx_u16m4(v_t2_u16, 3, v_s2, vl);
+    v_t3_u16 = __riscv_vwmaccu_vx_u16m4(v_t3_u16, 3, v_s3, vl);
+
+    v_u0 = __riscv_vnclipu_wx_u8m2(v_t0_u16, 2, __RISCV_VXRM_RNU, vl);
+    v_u1 = __riscv_vnclipu_wx_u8m2(v_t1_u16, 2, __RISCV_VXRM_RNU, vl);
+    v_u2 = __riscv_vnclipu_wx_u8m2(v_t2_u16, 2, __RISCV_VXRM_RNU, vl);
+    v_u3 = __riscv_vnclipu_wx_u8m2(v_t3_u16, 2, __RISCV_VXRM_RNU, vl);
+    // a0 = (src[0] * 3 + s[1] * 1 + 2) >> 2
+    v_u1_u16 = __riscv_vwaddu_vx_u16m4(v_u1, 0, vl);
+    v_u1_u16 = __riscv_vwmaccu_vx_u16m4(v_u1_u16, 3, v_u0, vl);
+    v_a0 = __riscv_vnclipu_wx_u8m2(v_u1_u16, 2, __RISCV_VXRM_RNU, vl);
+    // a1 = (src[1] * 1 + s[2] * 1 + 1) >> 1
+    v_a1 = __riscv_vaaddu_vv_u8m2(v_u1, v_u2, __RISCV_VXRM_RNU, vl);
+    // a2 = (src[2] * 1 + s[3] * 3 + 2) >> 2
+    v_u1_u16 = __riscv_vwaddu_vx_u16m4(v_u2, 0, vl);
+    v_u1_u16 = __riscv_vwmaccu_vx_u16m4(v_u1_u16, 3, v_u3, vl);
+    v_a2 = __riscv_vnclipu_wx_u8m2(v_u1_u16, 2, __RISCV_VXRM_RNU, vl);
+
+    v_dst = __riscv_vcreate_v_u8m2x3(v_a0, v_a1, v_a2);
+    __riscv_vsseg3e8_v_u8m2x3(dst_ptr, v_dst, vl);
+
+    w -= vl;
+    s += 4 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown34_0_Box_RVV(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst_ptr,
@@ -434,8 +805,69 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN34_1_BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleRowDown34_1_Box_RVV(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_ptr,
+                              int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  const uint8_t* s = src_ptr;
+  const uint8_t* t = src_ptr + src_stride;
+  do {
+    vuint8m2_t v_ave0, v_ave1, v_ave2, v_ave3;
+    vuint16m4_t v_u1_u16;
+    vuint8m2_t v_a0, v_a1, v_a2;
+    vuint8m2x3_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_s = __riscv_vlseg4e8_v_u8m2x4(s, vl);
+    vuint8m2_t v_s0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 0);
+    vuint8m2_t v_s1 = __riscv_vget_v_u8m2x4_u8m2(v_s, 1);
+    vuint8m2_t v_s2 = __riscv_vget_v_u8m2x4_u8m2(v_s, 2);
+    vuint8m2_t v_s3 = __riscv_vget_v_u8m2x4_u8m2(v_s, 3);
+
+    // Use round-to-nearest-up mode for vnclip & averaging add
+    if (src_stride == 0) {
+      v_ave0 = __riscv_vaaddu_vv_u8m2(v_s0, v_s0, __RISCV_VXRM_RNU, vl);
+      v_ave1 = __riscv_vaaddu_vv_u8m2(v_s1, v_s1, __RISCV_VXRM_RNU, vl);
+      v_ave2 = __riscv_vaaddu_vv_u8m2(v_s2, v_s2, __RISCV_VXRM_RNU, vl);
+      v_ave3 = __riscv_vaaddu_vv_u8m2(v_s3, v_s3, __RISCV_VXRM_RNU, vl);
+    } else {
+      vuint8m2x4_t v_t = __riscv_vlseg4e8_v_u8m2x4(t, vl);
+      vuint8m2_t v_t0 = __riscv_vget_v_u8m2x4_u8m2(v_t, 0);
+      vuint8m2_t v_t1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 1);
+      vuint8m2_t v_t2 = __riscv_vget_v_u8m2x4_u8m2(v_t, 2);
+      vuint8m2_t v_t3 = __riscv_vget_v_u8m2x4_u8m2(v_t, 3);
+      v_ave0 = __riscv_vaaddu_vv_u8m2(v_s0, v_t0, __RISCV_VXRM_RNU, vl);
+      v_ave1 = __riscv_vaaddu_vv_u8m2(v_s1, v_t1, __RISCV_VXRM_RNU, vl);
+      v_ave2 = __riscv_vaaddu_vv_u8m2(v_s2, v_t2, __RISCV_VXRM_RNU, vl);
+      v_ave3 = __riscv_vaaddu_vv_u8m2(v_s3, v_t3, __RISCV_VXRM_RNU, vl);
+      t += 4 * vl;
+    }
+    // a0 = (src[0] * 3 + s[1] * 1 + 2) >> 2
+    v_u1_u16 = __riscv_vwaddu_vx_u16m4(v_ave1, 0, vl);
+    v_u1_u16 = __riscv_vwmaccu_vx_u16m4(v_u1_u16, 3, v_ave0, vl);
+    v_a0 = __riscv_vnclipu_wx_u8m2(v_u1_u16, 2, __RISCV_VXRM_RNU, vl);
+
+    // a1 = (src[1] * 1 + s[2] * 1 + 1) >> 1
+    v_a1 = __riscv_vaaddu_vv_u8m2(v_ave1, v_ave2, __RISCV_VXRM_RNU, vl);
+
+    // a2 = (src[2] * 1 + s[3] * 3 + 2) >> 2
+    v_u1_u16 = __riscv_vwaddu_vx_u16m4(v_ave2, 0, vl);
+    v_u1_u16 = __riscv_vwmaccu_vx_u16m4(v_u1_u16, 3, v_ave3, vl);
+    v_a2 = __riscv_vnclipu_wx_u8m2(v_u1_u16, 2, __RISCV_VXRM_RNU, vl);
+
+    v_dst = __riscv_vcreate_v_u8m2x3(v_a0, v_a1, v_a2);
+    __riscv_vsseg3e8_v_u8m2x3(dst_ptr, v_dst, vl);
+
+    w -= vl;
+    s += 4 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown34_1_Box_RVV(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst_ptr,
@@ -490,8 +922,31 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN38_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowDown38_RVV(const uint8_t* src_ptr,
+                        ptrdiff_t src_stride,
+                        uint8_t* dst_ptr,
+                        int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  (void)src_stride;
+  assert(dst_width % 3 == 0);
+  do {
+    size_t vl = __riscv_vsetvl_e8m1(w);
+    vuint8m1x8_t v_src = __riscv_vlseg8e8_v_u8m1x8(src_ptr, vl);
+    vuint8m1_t v_s0 = __riscv_vget_v_u8m1x8_u8m1(v_src, 0);
+    vuint8m1_t v_s3 = __riscv_vget_v_u8m1x8_u8m1(v_src, 3);
+    vuint8m1_t v_s6 = __riscv_vget_v_u8m1x8_u8m1(v_src, 6);
+    vuint8m1x3_t v_dst = __riscv_vcreate_v_u8m1x3(v_s0, v_s3, v_s6);
+    __riscv_vsseg3e8_v_u8m1x3(dst_ptr, v_dst, vl);
+    w -= vl;
+    src_ptr += 8 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown38_RVV(const uint8_t* src_ptr,
                         ptrdiff_t src_stride,
                         uint8_t* dst_ptr,
@@ -511,8 +966,77 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN38_2_BOX_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowDown38_2_Box_RVV(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_ptr,
+                              int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  const uint16_t coeff_a = (65536u / 6u);
+  const uint16_t coeff_b = (65536u / 4u);
+  assert((dst_width % 3 == 0) && (dst_width > 0));
+  do {
+    vuint16m2_t v_e, v_f, v_g;
+    vuint8m1_t v_dst_e, v_dst_f, v_dst_g;
+    vuint8m1x3_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m1(w);
+    // s: e00, e10, e20, f00, f10, f20, g00, g10
+    vuint8m1x8_t v_s = __riscv_vlseg8e8_v_u8m1x8(src_ptr, vl);
+    vuint8m1_t v_s0 = __riscv_vget_v_u8m1x8_u8m1(v_s, 0);
+    vuint8m1_t v_s1 = __riscv_vget_v_u8m1x8_u8m1(v_s, 1);
+    vuint8m1_t v_s2 = __riscv_vget_v_u8m1x8_u8m1(v_s, 2);
+    vuint8m1_t v_s3 = __riscv_vget_v_u8m1x8_u8m1(v_s, 3);
+    vuint8m1_t v_s4 = __riscv_vget_v_u8m1x8_u8m1(v_s, 4);
+    vuint8m1_t v_s5 = __riscv_vget_v_u8m1x8_u8m1(v_s, 5);
+    vuint8m1_t v_s6 = __riscv_vget_v_u8m1x8_u8m1(v_s, 6);
+    vuint8m1_t v_s7 = __riscv_vget_v_u8m1x8_u8m1(v_s, 7);
+    // t: e01, e11, e21, f01, f11, f21, g01, g11
+    vuint8m1x8_t v_t = __riscv_vlseg8e8_v_u8m1x8(src_ptr + src_stride, vl);
+    vuint8m1_t v_t0 = __riscv_vget_v_u8m1x8_u8m1(v_t, 0);
+    vuint8m1_t v_t1 = __riscv_vget_v_u8m1x8_u8m1(v_t, 1);
+    vuint8m1_t v_t2 = __riscv_vget_v_u8m1x8_u8m1(v_t, 2);
+    vuint8m1_t v_t3 = __riscv_vget_v_u8m1x8_u8m1(v_t, 3);
+    vuint8m1_t v_t4 = __riscv_vget_v_u8m1x8_u8m1(v_t, 4);
+    vuint8m1_t v_t5 = __riscv_vget_v_u8m1x8_u8m1(v_t, 5);
+    vuint8m1_t v_t6 = __riscv_vget_v_u8m1x8_u8m1(v_t, 6);
+    vuint8m1_t v_t7 = __riscv_vget_v_u8m1x8_u8m1(v_t, 7);
+    // Calculate sum of [e00, e21] to v_e
+    // Calculate sum of [f00, f21] to v_f
+    // Calculate sum of [g00, g11] to v_g
+    vuint16m2_t v_e0 = __riscv_vwaddu_vv_u16m2(v_s0, v_t0, vl);
+    vuint16m2_t v_e1 = __riscv_vwaddu_vv_u16m2(v_s1, v_t1, vl);
+    vuint16m2_t v_e2 = __riscv_vwaddu_vv_u16m2(v_s2, v_t2, vl);
+    vuint16m2_t v_f0 = __riscv_vwaddu_vv_u16m2(v_s3, v_t3, vl);
+    vuint16m2_t v_f1 = __riscv_vwaddu_vv_u16m2(v_s4, v_t4, vl);
+    vuint16m2_t v_f2 = __riscv_vwaddu_vv_u16m2(v_s5, v_t5, vl);
+    vuint16m2_t v_g0 = __riscv_vwaddu_vv_u16m2(v_s6, v_t6, vl);
+    vuint16m2_t v_g1 = __riscv_vwaddu_vv_u16m2(v_s7, v_t7, vl);
+
+    v_e0 = __riscv_vadd_vv_u16m2(v_e0, v_e1, vl);
+    v_f0 = __riscv_vadd_vv_u16m2(v_f0, v_f1, vl);
+    v_e = __riscv_vadd_vv_u16m2(v_e0, v_e2, vl);
+    v_f = __riscv_vadd_vv_u16m2(v_f0, v_f2, vl);
+    v_g = __riscv_vadd_vv_u16m2(v_g0, v_g1, vl);
+
+    // Average in 16-bit fixed-point
+    v_e = __riscv_vmulhu_vx_u16m2(v_e, coeff_a, vl);
+    v_f = __riscv_vmulhu_vx_u16m2(v_f, coeff_a, vl);
+    v_g = __riscv_vmulhu_vx_u16m2(v_g, coeff_b, vl);
+    v_dst_e = __riscv_vnsrl_wx_u8m1(v_e, 0, vl);
+    v_dst_f = __riscv_vnsrl_wx_u8m1(v_f, 0, vl);
+    v_dst_g = __riscv_vnsrl_wx_u8m1(v_g, 0, vl);
+
+    v_dst = __riscv_vcreate_v_u8m1x3(v_dst_e, v_dst_f, v_dst_g);
+    __riscv_vsseg3e8_v_u8m1x3(dst_ptr, v_dst, vl);
+    w -= vl;
+    src_ptr += 8 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown38_2_Box_RVV(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst_ptr,
@@ -569,8 +1093,101 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWDOWN38_3_BOX_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowDown38_3_Box_RVV(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_ptr,
+                              int dst_width) {
+  size_t w = (size_t)dst_width / 3u;
+  const uint16_t coeff_a = (65536u / 9u);
+  const uint16_t coeff_b = (65536u / 6u);
+  assert((dst_width % 3 == 0) && (dst_width > 0));
+  do {
+    vuint16m2_t v_e0, v_e1, v_e2, v_e3, v_e4, v_e;
+    vuint16m2_t v_f0, v_f1, v_f2, v_f3, v_f4, v_f;
+    vuint16m2_t v_g0, v_g1, v_g2, v_g;
+    vuint8m1_t v_dst_e, v_dst_f, v_dst_g;
+    vuint8m1x3_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m1(w);
+    // s: e00, e10, e20, f00, f10, f20, g00, g10
+    vuint8m1x8_t v_s = __riscv_vlseg8e8_v_u8m1x8(src_ptr, vl);
+    vuint8m1_t v_s0 = __riscv_vget_v_u8m1x8_u8m1(v_s, 0);
+    vuint8m1_t v_s1 = __riscv_vget_v_u8m1x8_u8m1(v_s, 1);
+    vuint8m1_t v_s2 = __riscv_vget_v_u8m1x8_u8m1(v_s, 2);
+    vuint8m1_t v_s3 = __riscv_vget_v_u8m1x8_u8m1(v_s, 3);
+    vuint8m1_t v_s4 = __riscv_vget_v_u8m1x8_u8m1(v_s, 4);
+    vuint8m1_t v_s5 = __riscv_vget_v_u8m1x8_u8m1(v_s, 5);
+    vuint8m1_t v_s6 = __riscv_vget_v_u8m1x8_u8m1(v_s, 6);
+    vuint8m1_t v_s7 = __riscv_vget_v_u8m1x8_u8m1(v_s, 7);
+    // t: e01, e11, e21, f01, f11, f21, g01, g11
+    vuint8m1x8_t v_t = __riscv_vlseg8e8_v_u8m1x8(src_ptr + src_stride, vl);
+    vuint8m1_t v_t0 = __riscv_vget_v_u8m1x8_u8m1(v_t, 0);
+    vuint8m1_t v_t1 = __riscv_vget_v_u8m1x8_u8m1(v_t, 1);
+    vuint8m1_t v_t2 = __riscv_vget_v_u8m1x8_u8m1(v_t, 2);
+    vuint8m1_t v_t3 = __riscv_vget_v_u8m1x8_u8m1(v_t, 3);
+    vuint8m1_t v_t4 = __riscv_vget_v_u8m1x8_u8m1(v_t, 4);
+    vuint8m1_t v_t5 = __riscv_vget_v_u8m1x8_u8m1(v_t, 5);
+    vuint8m1_t v_t6 = __riscv_vget_v_u8m1x8_u8m1(v_t, 6);
+    vuint8m1_t v_t7 = __riscv_vget_v_u8m1x8_u8m1(v_t, 7);
+    // u: e02, e12, e22, f02, f12, f22, g02, g12
+    vuint8m1x8_t v_u = __riscv_vlseg8e8_v_u8m1x8(src_ptr + 2 * src_stride, vl);
+    vuint8m1_t v_u0 = __riscv_vget_v_u8m1x8_u8m1(v_u, 0);
+    vuint8m1_t v_u1 = __riscv_vget_v_u8m1x8_u8m1(v_u, 1);
+    vuint8m1_t v_u2 = __riscv_vget_v_u8m1x8_u8m1(v_u, 2);
+    vuint8m1_t v_u3 = __riscv_vget_v_u8m1x8_u8m1(v_u, 3);
+    vuint8m1_t v_u4 = __riscv_vget_v_u8m1x8_u8m1(v_u, 4);
+    vuint8m1_t v_u5 = __riscv_vget_v_u8m1x8_u8m1(v_u, 5);
+    vuint8m1_t v_u6 = __riscv_vget_v_u8m1x8_u8m1(v_u, 6);
+    vuint8m1_t v_u7 = __riscv_vget_v_u8m1x8_u8m1(v_u, 7);
+    // Calculate sum of [e00, e22]
+    v_e0 = __riscv_vwaddu_vv_u16m2(v_s0, v_t0, vl);
+    v_e1 = __riscv_vwaddu_vv_u16m2(v_s1, v_t1, vl);
+    v_e2 = __riscv_vwaddu_vv_u16m2(v_s2, v_t2, vl);
+    v_e3 = __riscv_vwaddu_vv_u16m2(v_u0, v_u1, vl);
+    v_e4 = __riscv_vwaddu_vx_u16m2(v_u2, 0, vl);
+
+    v_e0 = __riscv_vadd_vv_u16m2(v_e0, v_e1, vl);
+    v_e2 = __riscv_vadd_vv_u16m2(v_e2, v_e3, vl);
+    v_e0 = __riscv_vadd_vv_u16m2(v_e0, v_e4, vl);
+    v_e = __riscv_vadd_vv_u16m2(v_e0, v_e2, vl);
+    // Calculate sum of [f00, f22]
+    v_f0 = __riscv_vwaddu_vv_u16m2(v_s3, v_t3, vl);
+    v_f1 = __riscv_vwaddu_vv_u16m2(v_s4, v_t4, vl);
+    v_f2 = __riscv_vwaddu_vv_u16m2(v_s5, v_t5, vl);
+    v_f3 = __riscv_vwaddu_vv_u16m2(v_u3, v_u4, vl);
+    v_f4 = __riscv_vwaddu_vx_u16m2(v_u5, 0, vl);
+
+    v_f0 = __riscv_vadd_vv_u16m2(v_f0, v_f1, vl);
+    v_f2 = __riscv_vadd_vv_u16m2(v_f2, v_f3, vl);
+    v_f0 = __riscv_vadd_vv_u16m2(v_f0, v_f4, vl);
+    v_f = __riscv_vadd_vv_u16m2(v_f0, v_f2, vl);
+    // Calculate sum of [g00, g12]
+    v_g0 = __riscv_vwaddu_vv_u16m2(v_s6, v_t6, vl);
+    v_g1 = __riscv_vwaddu_vv_u16m2(v_s7, v_t7, vl);
+    v_g2 = __riscv_vwaddu_vv_u16m2(v_u6, v_u7, vl);
+
+    v_g = __riscv_vadd_vv_u16m2(v_g0, v_g1, vl);
+    v_g = __riscv_vadd_vv_u16m2(v_g, v_g2, vl);
+
+    // Average in 16-bit fixed-point
+    v_e = __riscv_vmulhu_vx_u16m2(v_e, coeff_a, vl);
+    v_f = __riscv_vmulhu_vx_u16m2(v_f, coeff_a, vl);
+    v_g = __riscv_vmulhu_vx_u16m2(v_g, coeff_b, vl);
+    v_dst_e = __riscv_vnsrl_wx_u8m1(v_e, 0, vl);
+    v_dst_f = __riscv_vnsrl_wx_u8m1(v_f, 0, vl);
+    v_dst_g = __riscv_vnsrl_wx_u8m1(v_g, 0, vl);
+
+    v_dst = __riscv_vcreate_v_u8m1x3(v_dst_e, v_dst_f, v_dst_g);
+    __riscv_vsseg3e8_v_u8m1x3(dst_ptr, v_dst, vl);
+    w -= vl;
+    src_ptr += 8 * vl;
+    dst_ptr += 3 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleRowDown38_3_Box_RVV(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst_ptr,
@@ -642,12 +1259,50 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 // ScaleUVRowUp2_(Bi)linear_RVV function is equal to other platforms'
 // ScaleRowUp2_(Bi)linear_Any_XXX. We process entire row in this function. Other
 // platforms only implement non-edge part of image and process edge with scalar.
 
 #ifdef HAS_SCALEROWUP2_LINEAR_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowUp2_Linear_RVV(const uint8_t* src_ptr,
+                            uint8_t* dst_ptr,
+                            int dst_width) {
+  size_t work_width = (size_t)dst_width - 1u;
+  size_t src_width = work_width >> 1u;
+  const uint8_t* work_src_ptr = src_ptr;
+  uint8_t* work_dst_ptr = dst_ptr + 1;
+  size_t vl = __riscv_vsetvlmax_e8m4();
+  vuint8m4_t v_3 = __riscv_vmv_v_x_u8m4(3, vl);
+  dst_ptr[0] = src_ptr[0];
+  while (src_width > 0) {
+    vuint8m4_t v_src0, v_src1, v_dst_odd, v_dst_even;
+    vuint16m8_t v_src0_u16, v_src1_u16;
+    vuint8m4x2_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m4(src_width);
+    v_src0 = __riscv_vle8_v_u8m4(work_src_ptr, vl);
+    v_src1 = __riscv_vle8_v_u8m4(work_src_ptr + 1, vl);
+
+    v_src0_u16 = __riscv_vwaddu_vx_u16m8(v_src0, 2, vl);
+    v_src1_u16 = __riscv_vwaddu_vx_u16m8(v_src1, 2, vl);
+    v_src0_u16 = __riscv_vwmaccu_vv_u16m8(v_src0_u16, v_3, v_src1, vl);
+    v_src1_u16 = __riscv_vwmaccu_vv_u16m8(v_src1_u16, v_3, v_src0, vl);
+
+    v_dst_odd = __riscv_vnsrl_wx_u8m4(v_src0_u16, 2, vl);
+    v_dst_even = __riscv_vnsrl_wx_u8m4(v_src1_u16, 2, vl);
+
+    v_dst = __riscv_vcreate_v_u8m4x2(v_dst_even, v_dst_odd);
+    __riscv_vsseg2e8_v_u8m4x2(work_dst_ptr, v_dst, vl);
+
+    src_width -= vl;
+    work_src_ptr += vl;
+    work_dst_ptr += 2 * vl;
+  }
+  dst_ptr[dst_width - 1] = src_ptr[(dst_width - 1) / 2];
+}
+#else
 void ScaleRowUp2_Linear_RVV(const uint8_t* src_ptr,
                             uint8_t* dst_ptr,
                             int dst_width) {
@@ -682,8 +1337,82 @@
   dst_ptr[dst_width - 1] = src_ptr[(dst_width - 1) / 2];
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEROWUP2_BILINEAR_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleRowUp2_Bilinear_RVV(const uint8_t* src_ptr,
+                              ptrdiff_t src_stride,
+                              uint8_t* dst_ptr,
+                              ptrdiff_t dst_stride,
+                              int dst_width) {
+  size_t work_width = ((size_t)dst_width - 1u) & ~1u;
+  size_t src_width = work_width >> 1u;
+  const uint8_t* work_s = src_ptr;
+  const uint8_t* work_t = src_ptr + src_stride;
+  const uint8_t* s = work_s;
+  const uint8_t* t = work_t;
+  uint8_t* d = dst_ptr;
+  uint8_t* e = dst_ptr + dst_stride;
+  uint8_t* work_d = d + 1;
+  uint8_t* work_e = e + 1;
+  size_t vl = __riscv_vsetvlmax_e16m4();
+  vuint16m4_t v_3_u16 = __riscv_vmv_v_x_u16m4(3, vl);
+  vuint8m2_t v_3_u8 = __riscv_vmv_v_x_u8m2(3, vl);
+  d[0] = (3 * s[0] + t[0] + 2) >> 2;
+  e[0] = (s[0] + 3 * t[0] + 2) >> 2;
+  while (src_width > 0) {
+    vuint8m2_t v_s0, v_s1, v_t0, v_t1;
+    vuint16m4_t v_s0_u16, v_s1_u16, v_t0_u16, v_t1_u16;
+    vuint16m4_t v_t0_u16_, v_t1_u16_;
+    vuint8m2_t v_dst0_even, v_dst0_odd, v_dst1_even, v_dst1_odd;
+    vuint8m2x2_t v_dst0, v_dst1;
+    size_t vl = __riscv_vsetvl_e8m2(src_width);
+    v_s0 = __riscv_vle8_v_u8m2(work_s, vl);
+    v_s1 = __riscv_vle8_v_u8m2(work_s + 1, vl);
+
+    v_s0_u16 = __riscv_vwaddu_vx_u16m4(v_s0, 2, vl);
+    v_s1_u16 = __riscv_vwaddu_vx_u16m4(v_s1, 2, vl);
+    v_s0_u16 = __riscv_vwmaccu_vv_u16m4(v_s0_u16, v_3_u8, v_s1, vl);
+    v_s1_u16 = __riscv_vwmaccu_vv_u16m4(v_s1_u16, v_3_u8, v_s0, vl);
+
+    v_t0 = __riscv_vle8_v_u8m2(work_t, vl);
+    v_t1 = __riscv_vle8_v_u8m2(work_t + 1, vl);
+
+    v_t0_u16 = __riscv_vwaddu_vx_u16m4(v_t0, 2, vl);
+    v_t1_u16 = __riscv_vwaddu_vx_u16m4(v_t1, 2, vl);
+    v_t0_u16 = __riscv_vwmaccu_vv_u16m4(v_t0_u16, v_3_u8, v_t1, vl);
+    v_t1_u16 = __riscv_vwmaccu_vv_u16m4(v_t1_u16, v_3_u8, v_t0, vl);
+
+    v_t0_u16_ = __riscv_vmv_v_v_u16m4(v_t0_u16, vl);
+    v_t1_u16_ = __riscv_vmv_v_v_u16m4(v_t1_u16, vl);
+
+    v_t0_u16 = __riscv_vmacc_vv_u16m4(v_t0_u16, v_3_u16, v_s0_u16, vl);
+    v_t1_u16 = __riscv_vmacc_vv_u16m4(v_t1_u16, v_3_u16, v_s1_u16, vl);
+    v_s0_u16 = __riscv_vmacc_vv_u16m4(v_s0_u16, v_3_u16, v_t0_u16_, vl);
+    v_s1_u16 = __riscv_vmacc_vv_u16m4(v_s1_u16, v_3_u16, v_t1_u16_, vl);
+
+    v_dst0_odd = __riscv_vnsrl_wx_u8m2(v_t0_u16, 4, vl);
+    v_dst0_even = __riscv_vnsrl_wx_u8m2(v_t1_u16, 4, vl);
+    v_dst1_odd = __riscv_vnsrl_wx_u8m2(v_s0_u16, 4, vl);
+    v_dst1_even = __riscv_vnsrl_wx_u8m2(v_s1_u16, 4, vl);
+
+    v_dst0 = __riscv_vcreate_v_u8m2x2(v_dst0_even, v_dst0_odd);
+    __riscv_vsseg2e8_v_u8m2x2(work_d, v_dst0, vl);
+    v_dst1 = __riscv_vcreate_v_u8m2x2(v_dst1_even, v_dst1_odd);
+    __riscv_vsseg2e8_v_u8m2x2(work_e, v_dst1, vl);
+    src_width -= vl;
+    work_s += vl;
+    work_t += vl;
+    work_d += 2 * vl;
+    work_e += 2 * vl;
+  }
+  d[dst_width - 1] =
+      (3 * s[(dst_width - 1) / 2] + t[(dst_width - 1) / 2] + 2) >> 2;
+  e[dst_width - 1] =
+      (s[(dst_width - 1) / 2] + 3 * t[(dst_width - 1) / 2] + 2) >> 2;
+}
+#else
 void ScaleRowUp2_Bilinear_RVV(const uint8_t* src_ptr,
                               ptrdiff_t src_stride,
                               uint8_t* dst_ptr,
@@ -754,6 +1483,7 @@
       (s[(dst_width - 1) / 2] + 3 * t[(dst_width - 1) / 2] + 2) >> 2;
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEUVROWDOWN2_RVV
 void ScaleUVRowDown2_RVV(const uint8_t* src_uv,
@@ -777,6 +1507,30 @@
 #endif
 
 #ifdef HAS_SCALEUVROWDOWN2LINEAR_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleUVRowDown2Linear_RVV(const uint8_t* src_uv,
+                               ptrdiff_t src_stride,
+                               uint8_t* dst_uv,
+                               int dst_width) {
+  size_t w = (size_t)dst_width;
+  const uint16_t* src = (const uint16_t*)src_uv;
+  (void)src_stride;
+  do {
+    size_t vl = __riscv_vsetvl_e16m4(w);
+    vuint16m4x2_t v_src = __riscv_vlseg2e16_v_u16m4x2(src, vl);
+    vuint16m4_t v_u0v0_16 = __riscv_vget_v_u16m4x2_u16m4(v_src, 0);
+    vuint16m4_t v_u1v1_16 = __riscv_vget_v_u16m4x2_u16m4(v_src, 1);
+    vuint8m4_t v_u0v0 = __riscv_vreinterpret_v_u16m4_u8m4(v_u0v0_16);
+    vuint8m4_t v_u1v1 = __riscv_vreinterpret_v_u16m4_u8m4(v_u1v1_16);
+    vuint8m4_t v_avg =
+        __riscv_vaaddu_vv_u8m4(v_u0v0, v_u1v1, __RISCV_VXRM_RNU, vl * 2);
+    __riscv_vse8_v_u8m4(dst_uv, v_avg, vl * 2);
+    w -= vl;
+    src += vl * 2;
+    dst_uv += vl * 2;
+  } while (w > 0);
+}
+#else
 void ScaleUVRowDown2Linear_RVV(const uint8_t* src_uv,
                                ptrdiff_t src_stride,
                                uint8_t* dst_uv,
@@ -803,8 +1557,50 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEUVROWDOWN2BOX_RVV
+#if defined(LIBYUV_RVV_HAS_TUPLE_TYPE) && defined(LIBYUV_RVV_HAS_VXRM_ARG)
+void ScaleUVRowDown2Box_RVV(const uint8_t* src_uv,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst_uv,
+                            int dst_width) {
+  const uint8_t* src_uv_row1 = src_uv + src_stride;
+  size_t w = (size_t)dst_width;
+  do {
+    size_t vl = __riscv_vsetvl_e8m2(w);
+    vuint8m2x4_t v_s = __riscv_vlseg4e8_v_u8m2x4(src_uv, vl);
+    vuint8m2_t v_u0_row0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 0);
+    vuint8m2_t v_v0_row0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 1);
+    vuint8m2_t v_u1_row0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 2);
+    vuint8m2_t v_v1_row0 = __riscv_vget_v_u8m2x4_u8m2(v_s, 3);
+    vuint8m2x4_t v_t = __riscv_vlseg4e8_v_u8m2x4(src_uv_row1, vl);
+    vuint8m2_t v_u0_row1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 0);
+    vuint8m2_t v_v0_row1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 1);
+    vuint8m2_t v_u1_row1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 2);
+    vuint8m2_t v_v1_row1 = __riscv_vget_v_u8m2x4_u8m2(v_t, 3);
+
+    vuint16m4_t v_u0u1_row0 = __riscv_vwaddu_vv_u16m4(v_u0_row0, v_u1_row0, vl);
+    vuint16m4_t v_u0u1_row1 = __riscv_vwaddu_vv_u16m4(v_u0_row1, v_u1_row1, vl);
+    vuint16m4_t v_v0v1_row0 = __riscv_vwaddu_vv_u16m4(v_v0_row0, v_v1_row0, vl);
+    vuint16m4_t v_v0v1_row1 = __riscv_vwaddu_vv_u16m4(v_v0_row1, v_v1_row1, vl);
+    vuint16m4_t v_sum0 = __riscv_vadd_vv_u16m4(v_u0u1_row0, v_u0u1_row1, vl);
+    vuint16m4_t v_sum1 = __riscv_vadd_vv_u16m4(v_v0v1_row0, v_v0v1_row1, vl);
+    vuint8m2_t v_dst_u =
+        __riscv_vnclipu_wx_u8m2(v_sum0, 2, __RISCV_VXRM_RNU, vl);
+    vuint8m2_t v_dst_v =
+        __riscv_vnclipu_wx_u8m2(v_sum1, 2, __RISCV_VXRM_RNU, vl);
+
+    vuint8m2x2_t v_dst_uv = __riscv_vcreate_v_u8m2x2(v_dst_u, v_dst_v);
+    __riscv_vsseg2e8_v_u8m2x2(dst_uv, v_dst_uv, vl);
+
+    dst_uv += 2 * vl;
+    src_uv += 4 * vl;
+    w -= vl;
+    src_uv_row1 += 4 * vl;
+  } while (w > 0);
+}
+#else
 void ScaleUVRowDown2Box_RVV(const uint8_t* src_uv,
                             ptrdiff_t src_stride,
                             uint8_t* dst_uv,
@@ -847,6 +1643,7 @@
   } while (w > 0);
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEUVROWDOWN4_RVV
 void ScaleUVRowDown4_RVV(const uint8_t* src_uv,
@@ -903,6 +1700,49 @@
 // scalar.
 
 #ifdef HAS_SCALEUVROWUP2_LINEAR_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleUVRowUp2_Linear_RVV(const uint8_t* src_ptr,
+                              uint8_t* dst_ptr,
+                              int dst_width) {
+  size_t work_width = ((size_t)dst_width - 1u) & ~1u;
+  uint16_t* work_dst_ptr = (uint16_t*)dst_ptr + 1;
+  const uint8_t* work_src_ptr = src_ptr;
+  size_t vl = __riscv_vsetvlmax_e8m4();
+  vuint8m4_t v_3_u8 = __riscv_vmv_v_x_u8m4(3, vl);
+  dst_ptr[0] = src_ptr[0];
+  dst_ptr[1] = src_ptr[1];
+  while (work_width > 0) {
+    vuint8m4_t v_uv0, v_uv1, v_dst_odd_u8, v_dst_even_u8;
+    vuint16m4_t v_dst_odd, v_dst_even;
+    vuint16m8_t v_uv0_u16, v_uv1_u16;
+    vuint16m4x2_t v_dst;
+    size_t vl = __riscv_vsetvl_e8m4(work_width);
+    v_uv0 = __riscv_vle8_v_u8m4(work_src_ptr, vl);
+    v_uv1 = __riscv_vle8_v_u8m4(work_src_ptr + 2, vl);
+
+    v_uv0_u16 = __riscv_vwaddu_vx_u16m8(v_uv0, 2, vl);
+    v_uv1_u16 = __riscv_vwaddu_vx_u16m8(v_uv1, 2, vl);
+
+    v_uv0_u16 = __riscv_vwmaccu_vv_u16m8(v_uv0_u16, v_3_u8, v_uv1, vl);
+    v_uv1_u16 = __riscv_vwmaccu_vv_u16m8(v_uv1_u16, v_3_u8, v_uv0, vl);
+
+    v_dst_odd_u8 = __riscv_vnsrl_wx_u8m4(v_uv0_u16, 2, vl);
+    v_dst_even_u8 = __riscv_vnsrl_wx_u8m4(v_uv1_u16, 2, vl);
+
+    v_dst_even = __riscv_vreinterpret_v_u8m4_u16m4(v_dst_even_u8);
+    v_dst_odd = __riscv_vreinterpret_v_u8m4_u16m4(v_dst_odd_u8);
+
+    v_dst = __riscv_vcreate_v_u16m4x2(v_dst_even, v_dst_odd);
+    __riscv_vsseg2e16_v_u16m4x2(work_dst_ptr, v_dst, vl / 2);
+
+    work_width -= vl;
+    work_src_ptr += vl;
+    work_dst_ptr += vl;
+  }
+  dst_ptr[2 * dst_width - 2] = src_ptr[((dst_width + 1) & ~1) - 2];
+  dst_ptr[2 * dst_width - 1] = src_ptr[((dst_width + 1) & ~1) - 1];
+}
+#else
 void ScaleUVRowUp2_Linear_RVV(const uint8_t* src_ptr,
                               uint8_t* dst_ptr,
                               int dst_width) {
@@ -943,8 +1783,98 @@
   dst_ptr[2 * dst_width - 1] = src_ptr[((dst_width + 1) & ~1) - 1];
 }
 #endif
+#endif
 
 #ifdef HAS_SCALEUVROWUP2_BILINEAR_RVV
+#ifdef LIBYUV_RVV_HAS_TUPLE_TYPE
+void ScaleUVRowUp2_Bilinear_RVV(const uint8_t* src_ptr,
+                                ptrdiff_t src_stride,
+                                uint8_t* dst_ptr,
+                                ptrdiff_t dst_stride,
+                                int dst_width) {
+  size_t work_width = ((size_t)dst_width - 1u) & ~1u;
+  const uint8_t* work_s = src_ptr;
+  const uint8_t* work_t = src_ptr + src_stride;
+  const uint8_t* s = work_s;
+  const uint8_t* t = work_t;
+  uint8_t* d = dst_ptr;
+  uint8_t* e = dst_ptr + dst_stride;
+  uint16_t* work_d = (uint16_t*)d + 1;
+  uint16_t* work_e = (uint16_t*)e + 1;
+  size_t vl = __riscv_vsetvlmax_e16m4();
+  vuint16m4_t v_3_u16 = __riscv_vmv_v_x_u16m4(3, vl);
+  vuint8m2_t v_3_u8 = __riscv_vmv_v_x_u8m2(3, vl);
+  d[0] = (3 * s[0] + t[0] + 2) >> 2;
+  e[0] = (s[0] + 3 * t[0] + 2) >> 2;
+  d[1] = (3 * s[1] + t[1] + 2) >> 2;
+  e[1] = (s[1] + 3 * t[1] + 2) >> 2;
+  while (work_width > 0) {
+    vuint8m2_t v_s0, v_s1, v_t0, v_t1;
+    vuint16m4_t v_s0_u16, v_s1_u16, v_t0_u16, v_t1_u16;
+    vuint16m4_t v_t0_u16_, v_t1_u16_;
+    vuint8m2_t v_dst0_odd_u8, v_dst0_even_u8, v_dst1_odd_u8, v_dst1_even_u8;
+    vuint16m2_t v_dst0_even, v_dst0_odd, v_dst1_even, v_dst1_odd;
+    vuint16m2x2_t v_dst0, v_dst1;
+    size_t vl = __riscv_vsetvl_e8m2(work_width);
+    v_s0 = __riscv_vle8_v_u8m2(work_s, vl);
+    v_s1 = __riscv_vle8_v_u8m2(work_s + 2, vl);
+
+    v_s0_u16 = __riscv_vwaddu_vx_u16m4(v_s0, 2, vl);
+    v_s1_u16 = __riscv_vwaddu_vx_u16m4(v_s1, 2, vl);
+    v_s0_u16 = __riscv_vwmaccu_vv_u16m4(v_s0_u16, v_3_u8, v_s1, vl);
+    v_s1_u16 = __riscv_vwmaccu_vv_u16m4(v_s1_u16, v_3_u8, v_s0, vl);
+
+    v_t0 = __riscv_vle8_v_u8m2(work_t, vl);
+    v_t1 = __riscv_vle8_v_u8m2(work_t + 2, vl);
+
+    v_t0_u16 = __riscv_vwaddu_vx_u16m4(v_t0, 2, vl);
+    v_t1_u16 = __riscv_vwaddu_vx_u16m4(v_t1, 2, vl);
+    v_t0_u16 = __riscv_vwmaccu_vv_u16m4(v_t0_u16, v_3_u8, v_t1, vl);
+    v_t1_u16 = __riscv_vwmaccu_vv_u16m4(v_t1_u16, v_3_u8, v_t0, vl);
+
+    v_t0_u16_ = __riscv_vmv_v_v_u16m4(v_t0_u16, vl);
+    v_t1_u16_ = __riscv_vmv_v_v_u16m4(v_t1_u16, vl);
+
+    v_t0_u16 = __riscv_vmacc_vv_u16m4(v_t0_u16, v_3_u16, v_s0_u16, vl);
+    v_t1_u16 = __riscv_vmacc_vv_u16m4(v_t1_u16, v_3_u16, v_s1_u16, vl);
+    v_s0_u16 = __riscv_vmacc_vv_u16m4(v_s0_u16, v_3_u16, v_t0_u16_, vl);
+    v_s1_u16 = __riscv_vmacc_vv_u16m4(v_s1_u16, v_3_u16, v_t1_u16_, vl);
+
+    v_dst0_odd_u8 = __riscv_vnsrl_wx_u8m2(v_t0_u16, 4, vl);
+    v_dst0_even_u8 = __riscv_vnsrl_wx_u8m2(v_t1_u16, 4, vl);
+    v_dst1_odd_u8 = __riscv_vnsrl_wx_u8m2(v_s0_u16, 4, vl);
+    v_dst1_even_u8 = __riscv_vnsrl_wx_u8m2(v_s1_u16, 4, vl);
+
+    v_dst0_even = __riscv_vreinterpret_v_u8m2_u16m2(v_dst0_even_u8);
+    v_dst0_odd = __riscv_vreinterpret_v_u8m2_u16m2(v_dst0_odd_u8);
+    v_dst1_even = __riscv_vreinterpret_v_u8m2_u16m2(v_dst1_even_u8);
+    v_dst1_odd = __riscv_vreinterpret_v_u8m2_u16m2(v_dst1_odd_u8);
+
+    v_dst0 = __riscv_vcreate_v_u16m2x2(v_dst0_even, v_dst0_odd);
+    __riscv_vsseg2e16_v_u16m2x2(work_d, v_dst0, vl / 2);
+    v_dst1 = __riscv_vcreate_v_u16m2x2(v_dst1_even, v_dst1_odd);
+    __riscv_vsseg2e16_v_u16m2x2(work_e, v_dst1, vl / 2);
+
+    work_width -= vl;
+    work_s += vl;
+    work_t += vl;
+    work_d += vl;
+    work_e += vl;
+  }
+  d[2 * dst_width - 2] =
+      (3 * s[((dst_width + 1) & ~1) - 2] + t[((dst_width + 1) & ~1) - 2] + 2) >>
+      2;
+  e[2 * dst_width - 2] =
+      (s[((dst_width + 1) & ~1) - 2] + 3 * t[((dst_width + 1) & ~1) - 2] + 2) >>
+      2;
+  d[2 * dst_width - 1] =
+      (3 * s[((dst_width + 1) & ~1) - 1] + t[((dst_width + 1) & ~1) - 1] + 2) >>
+      2;
+  e[2 * dst_width - 1] =
+      (s[((dst_width + 1) & ~1) - 1] + 3 * t[((dst_width + 1) & ~1) - 1] + 2) >>
+      2;
+}
+#else
 void ScaleUVRowUp2_Bilinear_RVV(const uint8_t* src_ptr,
                                 ptrdiff_t src_stride,
                                 uint8_t* dst_ptr,
@@ -1030,6 +1960,7 @@
       2;
 }
 #endif
+#endif
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/source/scale_sme.cc b/source/scale_sme.cc
new file mode 100644
index 0000000..fa74569
--- /dev/null
+++ b/source/scale_sme.cc
@@ -0,0 +1,555 @@
+/*
+ *  Copyright 2024 The LibYuv 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 "libyuv/scale_row.h"
+
+#ifdef __cplusplus
+namespace libyuv {
+extern "C" {
+#endif
+
+#if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \
+    defined(__aarch64__)
+
+__arm_locally_streaming void ScaleRowDown2_SME(const uint8_t* src_ptr,
+                                               ptrdiff_t src_stride,
+                                               uint8_t* dst,
+                                               int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.b                                         \n"
+      "ld2b     {z0.b, z1.b}, p0/z, [%[src_ptr]]             \n"
+      "incb     %[src_ptr], all, mul #2                      \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1b     {z1.b}, p0, [%[dst_ptr]]                     \n"
+      "incb     %[dst_ptr]                                   \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.b, wzr, %w[dst_width]                     \n"
+      "ld2b     {z0.b, z1.b}, p0/z, [%[src_ptr]]             \n"
+      "st1b     {z1.b}, p0, [%[dst_ptr]]                     \n"
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ScaleRowDown2_16_SME(const uint16_t* src_ptr,
+                                                  ptrdiff_t src_stride,
+                                                  uint16_t* dst,
+                                                  int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.h                                         \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_ptr]]             \n"
+      "incb     %[src_ptr], all, mul #2                      \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1h     {z1.h}, p0, [%[dst_ptr]]                     \n"
+      "incb     %[dst_ptr]                                   \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_ptr]]             \n"
+      "st1h     {z1.h}, p0, [%[dst_ptr]]                     \n"
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ScaleRowDown2Linear_SME(const uint8_t* src_ptr,
+                                                     ptrdiff_t src_stride,
+                                                     uint8_t* dst,
+                                                     int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.b                                         \n"
+      "ld2b     {z0.b, z1.b}, p0/z, [%[src_ptr]]             \n"
+      "incb     %[src_ptr], all, mul #2                      \n"
+      "urhadd   z0.b, p0/m, z0.b, z1.b                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1b     {z0.b}, p0, [%[dst_ptr]]                     \n"
+      "incb     %[dst_ptr]                                   \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.b, wzr, %w[dst_width]                     \n"
+      "ld2b     {z0.b, z1.b}, p0/z, [%[src_ptr]]             \n"
+      "urhadd   z0.b, p0/m, z0.b, z1.b                       \n"
+      "st1b     {z0.b}, p0, [%[dst_ptr]]                     \n"
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ScaleRowDown2Linear_16_SME(const uint16_t* src_ptr,
+                                                        ptrdiff_t src_stride,
+                                                        uint16_t* dst,
+                                                        int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.h                                         \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_ptr]]             \n"
+      "incb     %[src_ptr], all, mul #2                      \n"
+      "urhadd   z0.h, p0/m, z0.h, z1.h                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1h     {z0.h}, p0, [%[dst_ptr]]                     \n"
+      "incb     %[dst_ptr]                                   \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_ptr]]             \n"
+      "urhadd   z0.h, p0/m, z0.h, z1.h                       \n"
+      "st1h     {z0.h}, p0, [%[dst_ptr]]                     \n"
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+#define SCALEROWDOWN2BOX_SVE                                 \
+  "ld2b     {z0.b, z1.b}, p0/z, [%[src_ptr]]             \n" \
+  "ld2b     {z2.b, z3.b}, p0/z, [%[src2_ptr]]            \n" \
+  "incb     %[src_ptr], all, mul #2                      \n" \
+  "incb     %[src2_ptr], all, mul #2                     \n" \
+  "uaddlb   z4.h, z0.b, z1.b                             \n" \
+  "uaddlt   z5.h, z0.b, z1.b                             \n" \
+  "uaddlb   z6.h, z2.b, z3.b                             \n" \
+  "uaddlt   z7.h, z2.b, z3.b                             \n" \
+  "add      z4.h, z4.h, z6.h                             \n" \
+  "add      z5.h, z5.h, z7.h                             \n" \
+  "rshrnb   z0.b, z4.h, #2                               \n" \
+  "rshrnt   z0.b, z5.h, #2                               \n" \
+  "subs     %w[dst_width], %w[dst_width], %w[vl]         \n" \
+  "st1b     {z0.b}, p0, [%[dst_ptr]]                     \n" \
+  "incb     %[dst_ptr]                                   \n"
+
+__arm_locally_streaming void ScaleRowDown2Box_SME(const uint8_t* src_ptr,
+                                                  ptrdiff_t src_stride,
+                                                  uint8_t* dst,
+                                                  int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  const uint8_t* src2_ptr = src_ptr + src_stride;
+  int vl;
+  asm volatile(
+      "cntb     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.b                                         \n"
+      "1:                                                    \n"  //
+      SCALEROWDOWN2BOX_SVE
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.b, wzr, %w[dst_width]                     \n"  //
+      SCALEROWDOWN2BOX_SVE
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [src2_ptr] "+r"(src2_ptr),    // %[src2_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0");
+}
+
+#undef SCALEROWDOWN2BOX_SVE
+
+#define SCALEROWDOWN2BOX_16_SVE                              \
+  "ld2h     {z0.h, z1.h}, p0/z, [%[src_ptr]]             \n" \
+  "ld2h     {z2.h, z3.h}, p0/z, [%[src2_ptr]]            \n" \
+  "incb     %[src_ptr], all, mul #2                      \n" \
+  "incb     %[src2_ptr], all, mul #2                     \n" \
+  "uaddlb   z4.s, z0.h, z1.h                             \n" \
+  "uaddlt   z5.s, z0.h, z1.h                             \n" \
+  "uaddlb   z6.s, z2.h, z3.h                             \n" \
+  "uaddlt   z7.s, z2.h, z3.h                             \n" \
+  "add      z4.s, z4.s, z6.s                             \n" \
+  "add      z5.s, z5.s, z7.s                             \n" \
+  "rshrnb   z0.h, z4.s, #2                               \n" \
+  "rshrnt   z0.h, z5.s, #2                               \n" \
+  "subs     %w[dst_width], %w[dst_width], %w[vl]         \n" \
+  "st1h     {z0.h}, p0, [%[dst_ptr]]                     \n" \
+  "incb     %[dst_ptr]                                   \n"
+
+__arm_locally_streaming void ScaleRowDown2Box_16_SME(const uint16_t* src_ptr,
+                                                     ptrdiff_t src_stride,
+                                                     uint16_t* dst,
+                                                     int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  const uint16_t* src2_ptr = src_ptr + src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.h                                         \n"
+      "1:                                                    \n"  //
+      SCALEROWDOWN2BOX_16_SVE
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"  //
+      SCALEROWDOWN2BOX_16_SVE
+
+      "99:                                                   \n"
+      : [src_ptr] "+r"(src_ptr),      // %[src_ptr]
+        [src2_ptr] "+r"(src2_ptr),    // %[src2_ptr]
+        [dst_ptr] "+r"(dst),          // %[dst_ptr]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0");
+}
+
+#undef SCALEROWDOWN2BOX_16_SVE
+
+__arm_locally_streaming void ScaleUVRowDown2_SME(const uint8_t* src_uv,
+                                                 ptrdiff_t src_stride,
+                                                 uint8_t* dst_uv,
+                                                 int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.b                                         \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_uv]]              \n"
+      "incb     %[src_uv], all, mul #2                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1h     {z1.h}, p0, [%[dst_uv]]                      \n"
+      "incb     %[dst_uv]                                    \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_uv]]              \n"
+      "st1h     {z1.h}, p0, [%[dst_uv]]                      \n"
+
+      "99:                                                   \n"
+      : [src_uv] "+r"(src_uv),        // %[src_uv]
+        [dst_uv] "+r"(dst_uv),        // %[dst_uv]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ScaleUVRowDown2Linear_SME(const uint8_t* src_uv,
+                                                       ptrdiff_t src_stride,
+                                                       uint8_t* dst_uv,
+                                                       int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "ptrue    p1.b                                         \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.h                                         \n"
+      "1:                                                    \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_uv]]              \n"
+      "incb     %[src_uv], all, mul #2                       \n"
+      "urhadd   z0.b, p1/m, z0.b, z1.b                       \n"
+      "st1h     {z0.h}, p0, [%[dst_uv]]                      \n"
+      "incb     %[dst_uv], all, mul #1                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"
+      "ld2h     {z0.h, z1.h}, p0/z, [%[src_uv]]              \n"
+      "urhadd   z0.b, p1/m, z0.b, z1.b                       \n"
+      "st1h     {z0.h}, p0, [%[dst_uv]]                      \n"
+
+      "99:                                                   \n"
+      : [src_uv] "+r"(src_uv),        // %[src_uv]
+        [dst_uv] "+r"(dst_uv),        // %[dst_uv]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "z0", "z1", "p0", "p1");
+}
+
+#define SCALEUVROWDOWN2BOX_SVE                               \
+  "ld2h     {z0.h, z1.h}, p0/z, [%[src_uv]]              \n" \
+  "ld2h     {z2.h, z3.h}, p0/z, [%[src2_uv]]             \n" \
+  "incb     %[src_uv], all, mul #2                       \n" \
+  "incb     %[src2_uv], all, mul #2                      \n" \
+  "uaddlb   z4.h, z0.b, z1.b                             \n" \
+  "uaddlt   z5.h, z0.b, z1.b                             \n" \
+  "uaddlb   z6.h, z2.b, z3.b                             \n" \
+  "uaddlt   z7.h, z2.b, z3.b                             \n" \
+  "add      z4.h, z4.h, z6.h                             \n" \
+  "add      z5.h, z5.h, z7.h                             \n" \
+  "rshrnb   z0.b, z4.h, #2                               \n" \
+  "rshrnt   z0.b, z5.h, #2                               \n" \
+  "st1h     {z0.h}, p0, [%[dst_uv]]                      \n" \
+  "incb     %[dst_uv], all, mul #1                       \n"
+
+__arm_locally_streaming void ScaleUVRowDown2Box_SME(const uint8_t* src_uv,
+                                                    ptrdiff_t src_stride,
+                                                    uint8_t* dst_uv,
+                                                    int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  const uint8_t* src2_uv = src_uv + src_stride;
+  int vl;
+  asm volatile(
+      "cnth     %x[vl]                                       \n"
+      "ptrue    p1.b                                         \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.h                                         \n"
+      "1:                                                    \n"  //
+      SCALEUVROWDOWN2BOX_SVE
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.h, wzr, %w[dst_width]                     \n"  //
+      SCALEUVROWDOWN2BOX_SVE
+
+      "99:                                                   \n"
+      : [src_uv] "+r"(src_uv),        // %[src_uv]
+        [src2_uv] "+r"(src2_uv),      // %[src2_uv]
+        [dst_uv] "+r"(dst_uv),        // %[dst_uv]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0", "p1");
+}
+
+#undef SCALEUVROWDOWN2BOX_SVE
+
+__arm_locally_streaming void ScaleARGBRowDown2_SME(const uint8_t* src_argb,
+                                                   ptrdiff_t src_stride,
+                                                   uint8_t* dst_argb,
+                                                   int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cntw     %x[vl]                                       \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "1:                                                    \n"
+      "ptrue    p0.b                                         \n"
+      "ld2w     {z0.s, z1.s}, p0/z, [%[src_argb]]            \n"
+      "incb     %[src_argb], all, mul #2                     \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "st1w     {z1.s}, p0, [%[dst_argb]]                    \n"
+      "incb     %[dst_argb]                                  \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.s, wzr, %w[dst_width]                     \n"
+      "ld2w     {z0.s, z1.s}, p0/z, [%[src_argb]]            \n"
+      "st1w     {z1.s}, p0, [%[dst_argb]]                    \n"
+
+      "99:                                                   \n"
+      : [src_argb] "+r"(src_argb),    // %[src_argb]
+        [dst_argb] "+r"(dst_argb),    // %[dst_argb]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0");
+}
+
+__arm_locally_streaming void ScaleARGBRowDown2Linear_SME(
+    const uint8_t* src_argb,
+    ptrdiff_t src_stride,
+    uint8_t* dst_argb,
+    int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  (void)src_stride;
+  int vl;
+  asm volatile(
+      "cntw     %x[vl]                                       \n"
+      "ptrue    p1.b                                         \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.s                                         \n"
+      "1:                                                    \n"
+      "ld2w     {z0.s, z1.s}, p0/z, [%[src_argb]]            \n"
+      "incb     %[src_argb], all, mul #2                     \n"
+      "urhadd   z0.b, p1/m, z0.b, z1.b                       \n"
+      "st1w     {z0.s}, p0, [%[dst_argb]]                    \n"
+      "incb     %[dst_argb], all, mul #1                     \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.s, wzr, %w[dst_width]                     \n"
+      "ld2w     {z0.s, z1.s}, p0/z, [%[src_argb]]            \n"
+      "urhadd   z0.b, p1/m, z0.b, z1.b                       \n"
+      "st1w     {z0.s}, p0, [%[dst_argb]]                    \n"
+
+      "99:                                                   \n"
+      : [src_argb] "+r"(src_argb),    // %[src_argb]
+        [dst_argb] "+r"(dst_argb),    // %[dst_argb]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "p0", "p1");
+}
+
+#define SCALEARGBROWDOWN2BOX_SVE                               \
+  "ld2w     {z0.s, z1.s}, p0/z, [%[src_argb]]              \n" \
+  "ld2w     {z2.s, z3.s}, p0/z, [%[src2_argb]]             \n" \
+  "incb     %[src_argb], all, mul #2                       \n" \
+  "incb     %[src2_argb], all, mul #2                      \n" \
+  "uaddlb   z4.h, z0.b, z1.b                               \n" \
+  "uaddlt   z5.h, z0.b, z1.b                               \n" \
+  "uaddlb   z6.h, z2.b, z3.b                               \n" \
+  "uaddlt   z7.h, z2.b, z3.b                               \n" \
+  "add      z4.h, z4.h, z6.h                               \n" \
+  "add      z5.h, z5.h, z7.h                               \n" \
+  "rshrnb   z0.b, z4.h, #2                                 \n" \
+  "rshrnt   z0.b, z5.h, #2                                 \n" \
+  "st1w     {z0.s}, p0, [%[dst_argb]]                      \n" \
+  "incb     %[dst_argb], all, mul #1                       \n"
+
+__arm_locally_streaming void ScaleARGBRowDown2Box_SME(const uint8_t* src_argb,
+                                                      ptrdiff_t src_stride,
+                                                      uint8_t* dst_argb,
+                                                      int dst_width) {
+  // Streaming-SVE only, no use of ZA tile.
+  const uint8_t* src2_argb = src_argb + src_stride;
+  int vl;
+  asm volatile(
+      "cntw     %x[vl]                                       \n"
+      "ptrue    p1.b                                         \n"
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.lt     2f                                           \n"
+
+      "ptrue    p0.s                                         \n"
+      "1:                                                    \n"  //
+      SCALEARGBROWDOWN2BOX_SVE
+      "subs     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.ge     1b                                           \n"
+
+      "2:                                                    \n"
+      "adds     %w[dst_width], %w[dst_width], %w[vl]         \n"
+      "b.eq     99f                                          \n"
+
+      "whilelt  p0.s, wzr, %w[dst_width]                     \n"  //
+      SCALEARGBROWDOWN2BOX_SVE
+
+      "99:                                                   \n"
+      : [src_argb] "+r"(src_argb),    // %[src_argb]
+        [src2_argb] "+r"(src2_argb),  // %[src2_argb]
+        [dst_argb] "+r"(dst_argb),    // %[dst_argb]
+        [dst_width] "+r"(dst_width),  // %[dst_width]
+        [vl] "=r"(vl)                 // %[vl]
+      :
+      : "memory", "cc", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0",
+        "p1");
+}
+
+#endif  // !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) &&
+        // defined(__aarch64__)
+
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace libyuv
+#endif
diff --git a/source/scale_uv.cc b/source/scale_uv.cc
index 0931c89..700d1b2 100644
--- a/source/scale_uv.cc
+++ b/source/scale_uv.cc
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "libyuv/scale.h"
+#include "libyuv/scale_uv.h"
 
 #include <assert.h>
 #include <string.h>
@@ -104,14 +104,6 @@
     }
   }
 #endif
-#if defined(HAS_SCALEUVROWDOWN2BOX_NEON)
-  if (TestCpuFlag(kCpuHasNEON) && filtering) {
-    ScaleUVRowDown2 = ScaleUVRowDown2Box_Any_NEON;
-    if (IS_ALIGNED(dst_width, 8)) {
-      ScaleUVRowDown2 = ScaleUVRowDown2Box_NEON;
-    }
-  }
-#endif
 #if defined(HAS_SCALEUVROWDOWN2_NEON)
   if (TestCpuFlag(kCpuHasNEON)) {
     ScaleUVRowDown2 =
@@ -128,6 +120,13 @@
     }
   }
 #endif
+#if defined(HAS_SCALEUVROWDOWN2_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleUVRowDown2 = filtering == kFilterNone     ? ScaleUVRowDown2_SME
+                      : filtering == kFilterLinear ? ScaleUVRowDown2Linear_SME
+                                                   : ScaleUVRowDown2Box_SME;
+  }
+#endif
 #if defined(HAS_SCALEUVROWDOWN2_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     ScaleUVRowDown2 =
@@ -242,6 +241,11 @@
     }
   }
 #endif
+#if defined(HAS_SCALEUVROWDOWN2BOX_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    ScaleUVRowDown2 = ScaleUVRowDown2Box_SME;
+  }
+#endif
 #if defined(HAS_SCALEUVROWDOWN2BOX_RVV)
   if (TestCpuFlag(kCpuHasRVV)) {
     ScaleUVRowDown2 = ScaleUVRowDown2Box_RVV;
@@ -327,10 +331,16 @@
     }
   }
 #endif
-#if defined(HAS_SCALEUVROWDOWNEVEN_RVV)
+#if defined(HAS_SCALEUVROWDOWNEVEN_RVV) || defined(HAS_SCALEUVROWDOWN4_RVV)
   if (TestCpuFlag(kCpuHasRVV) && !filtering) {
-    ScaleUVRowDownEven =
-        (col_step == 4) ? ScaleUVRowDown4_RVV : ScaleUVRowDownEven_RVV;
+#if defined(HAS_SCALEUVROWDOWNEVEN_RVV)
+    ScaleUVRowDownEven = ScaleUVRowDownEven_RVV;
+#endif
+#if defined(HAS_SCALEUVROWDOWN4_RVV)
+    if (col_step == 4) {
+      ScaleUVRowDownEven = ScaleUVRowDown4_RVV;
+    }
+#endif
   }
 #endif
 
@@ -404,6 +414,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -525,6 +540,11 @@
     }
   }
 #endif
+#if defined(HAS_INTERPOLATEROW_SME)
+  if (TestCpuFlag(kCpuHasSME)) {
+    InterpolateRow = InterpolateRow_SME;
+  }
+#endif
 #if defined(HAS_INTERPOLATEROW_MSA)
   if (TestCpuFlag(kCpuHasMSA)) {
     InterpolateRow = InterpolateRow_Any_MSA;
@@ -680,6 +700,7 @@
   int dy;
 
   // This function can only scale up by 2 times horizontally.
+  (void)src_width;
   assert(src_width == ((dst_width + 1) / 2));
 
 #ifdef HAS_SCALEUVROWUP2_LINEAR_SSSE3
@@ -738,6 +759,7 @@
   int x;
 
   // This function can only scale up by 2 times.
+  (void)src_width;
   assert(src_width == ((dst_width + 1) / 2));
   assert(src_height == ((dst_height + 1) / 2));
 
@@ -799,6 +821,7 @@
   int dy;
 
   // This function can only scale up by 2 times horizontally.
+  (void)src_width;
   assert(src_width == ((dst_width + 1) / 2));
 
 #ifdef HAS_SCALEUVROWUP2_LINEAR_16_SSE41
@@ -851,6 +874,7 @@
   int x;
 
   // This function can only scale up by 2 times.
+  (void)src_width;
   assert(src_width == ((dst_width + 1) / 2));
   assert(src_height == ((dst_height + 1) / 2));
 
@@ -1045,7 +1069,7 @@
       // Optimized even scale down. ie 2, 4, 6, 8, 10x.
       if (!(dx & 0x10000) && !(dy & 0x10000)) {
 #if HAS_SCALEUVDOWN2
-        if (dx == 0x20000) {
+        if (dx == 0x20000 && dy == 0x20000) {
           // Optimized 1/2 downsample.
           ScaleUVDown2(src_width, src_height, clip_width, clip_height,
                        src_stride, dst_stride, src, dst, x, dx, y, dy,
@@ -1054,7 +1078,7 @@
         }
 #endif
 #if HAS_SCALEUVDOWN4BOX
-        if (dx == 0x40000 && filtering == kFilterBox) {
+        if (dx == 0x40000 && dy == 0x40000 && filtering == kFilterBox) {
           // Optimized 1/4 box downsample.
           return ScaleUVDown4Box(src_width, src_height, clip_width, clip_height,
                                  src_stride, dst_stride, src, dst, x, dx, y,
diff --git a/source/scale_win.cc b/source/scale_win.cc
index ea1f95c..32c0506 100644
--- a/source/scale_win.cc
+++ b/source/scale_win.cc
@@ -17,8 +17,8 @@
 #endif
 
 // This module is for 32 bit Visual C x86
-#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && \
-    !defined(__clang__) && defined(_M_IX86)
+#if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && defined(_M_IX86) && \
+    (!defined(__clang__) || defined(LIBYUV_ENABLE_ROWWIN))
 
 // Offsets for source bytes 0 to 9
 static const uvec8 kShuf0 = {0,   1,   3,   4,   5,   7,   8,   9,
diff --git a/tools_libyuv/autoroller/roll_deps.py b/tools_libyuv/autoroller/roll_deps.py
index d5c1089..472cbe6 100755
--- a/tools_libyuv/autoroller/roll_deps.py
+++ b/tools_libyuv/autoroller/roll_deps.py
@@ -20,13 +20,20 @@
 import sys
 import urllib.request
 
+def FindRootPath():
+    """Returns the absolute path to the highest level repo root.
 
-def FindSrcDirPath():
-  """Returns the abs path to the src/ dir of the project."""
-  src_dir = os.path.dirname(os.path.abspath(__file__))
-  while os.path.basename(src_dir) != 'src':
-    src_dir = os.path.normpath(os.path.join(src_dir, os.pardir))
-  return src_dir
+    If this repo is checked out as a submodule of the chromium/src
+    superproject, this returns the superproect root. Otherwise, it returns the
+    webrtc/src repo root.
+    """
+    root_dir = os.path.dirname(os.path.abspath(__file__))
+    while os.path.basename(root_dir) not in ('src', 'chromium'):
+        par_dir = os.path.normpath(os.path.join(root_dir, os.pardir))
+        if par_dir == root_dir:
+            raise RuntimeError('Could not find the repo root.')
+        root_dir = par_dir
+    return root_dir
 
 
 # Skip these dependencies (list without solution name prefix).
@@ -41,15 +48,12 @@
 # but we pull it through a subtree mirror, so therefore it isn't listed in
 # Chromium's deps but it is in ours.
 LIBYUV_ONLY_DEPS = [
-    'src/base',
     'src/build',
     'src/buildtools',
     'src/ios',
     'src/testing',
     'src/third_party',
     'src/third_party/android_support_test_runner',
-    'src/third_party/bazel',
-    'src/third_party/bouncycastle',
     'src/third_party/errorprone/lib',
     'src/third_party/findbugs',
     'src/third_party/gson',
@@ -75,8 +79,8 @@
 ROLL_BRANCH_NAME = 'roll_chromium_revision'
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-CHECKOUT_SRC_DIR = FindSrcDirPath()
-CHECKOUT_ROOT_DIR = os.path.realpath(os.path.join(CHECKOUT_SRC_DIR, os.pardir))
+CHECKOUT_ROOT_DIR = FindRootPath()
+GCLIENT_ROOT_DIR = os.path.realpath(os.path.join(CHECKOUT_ROOT_DIR, os.pardir))
 
 # Copied from tools/android/roll/android_deps/.../BuildConfigGenerator.groovy.
 ANDROID_DEPS_START = r'=== ANDROID_DEPS Generated Code Start ==='
@@ -84,172 +88,188 @@
 # Location of automically gathered android deps.
 ANDROID_DEPS_PATH = 'src/third_party/android_deps/'
 
-sys.path.append(os.path.join(CHECKOUT_SRC_DIR, 'build'))
-import find_depot_tools
+sys.path.append(os.path.join(CHECKOUT_ROOT_DIR, 'build'))
+import find_depot_tools  # pylint: disable=wrong-import-position
 
 find_depot_tools.add_depot_tools_to_path()
 
 CLANG_UPDATE_SCRIPT_URL_PATH = 'tools/clang/scripts/update.py'
-CLANG_UPDATE_SCRIPT_LOCAL_PATH = os.path.join(CHECKOUT_SRC_DIR, 'tools',
-                                              'clang', 'scripts', 'update.py')
+CLANG_UPDATE_SCRIPT_LOCAL_PATH = os.path.join(
+    CHECKOUT_ROOT_DIR, 'tools', 'clang', 'scripts', 'update.py'
+)
 
 DepsEntry = collections.namedtuple('DepsEntry', 'path url revision')
-ChangedDep = collections.namedtuple('ChangedDep',
-                                    'path url current_rev new_rev')
+ChangedDep = collections.namedtuple(
+    'ChangedDep', 'path url current_rev new_rev'
+)
 CipdDepsEntry = collections.namedtuple('CipdDepsEntry', 'path packages')
+GcsDepsEntry = collections.namedtuple('GcsDepsEntry', 'path bucket objects')
 VersionEntry = collections.namedtuple('VersionEntry', 'version')
 ChangedCipdPackage = collections.namedtuple(
-    'ChangedCipdPackage', 'path package current_version new_version')
+    'ChangedCipdPackage', 'path package current_version new_version'
+)
 ChangedVersionEntry = collections.namedtuple(
-    'ChangedVersionEntry', 'path current_version new_version')
+    'ChangedVersionEntry', 'path current_version new_version'
+)
 
-ChromiumRevisionUpdate = collections.namedtuple('ChromiumRevisionUpdate',
-                                                ('current_chromium_rev '
-                                                 'new_chromium_rev '))
+ChromiumRevisionUpdate = collections.namedtuple(
+    'ChromiumRevisionUpdate', 'current_chromium_rev new_chromium_rev '
+)
 
 
 class RollError(Exception):
-  pass
+    pass
 
 
 def StrExpansion():
-  return lambda str_value: str_value
+    return lambda str_value: str_value
 
 
 def VarLookup(local_scope):
-  return lambda var_name: local_scope['vars'][var_name]
+    return lambda var_name: local_scope['vars'][var_name]
 
 
 def ParseDepsDict(deps_content):
-  local_scope = {}
-  global_scope = {
-      'Str': StrExpansion(),
-      'Var': VarLookup(local_scope),
-      'deps_os': {},
-  }
-  exec(deps_content, global_scope, local_scope)
-  return local_scope
+    local_scope = {}
+    global_scope = {
+        'Str': StrExpansion(),
+        'Var': VarLookup(local_scope),
+        'deps_os': {},
+    }
+    exec(deps_content, global_scope, local_scope)
+    return local_scope
 
 
 def ParseLocalDepsFile(filename):
-  with open(filename, 'rb') as f:
-    deps_content = f.read().decode('utf-8')
-  return ParseDepsDict(deps_content)
+    with open(filename, 'rb') as f:
+        deps_content = f.read().decode('utf-8')
+    return ParseDepsDict(deps_content)
 
 
 def ParseCommitPosition(commit_message):
-  for line in reversed(commit_message.splitlines()):
-    m = COMMIT_POSITION_RE.match(line.strip())
-    if m:
-      return int(m.group(1))
-  logging.error('Failed to parse commit position id from:\n%s\n',
-                commit_message)
-  sys.exit(-1)
+    for line in reversed(commit_message.splitlines()):
+        m = COMMIT_POSITION_RE.match(line.strip())
+        if m:
+            return int(m.group(1))
+    logging.error(
+        'Failed to parse commit position id from:\n%s\n', commit_message
+    )
+    sys.exit(-1)
 
 
-def _RunCommand(command,
-                working_dir=None,
-                ignore_exit_code=False,
-                extra_env=None,
-                input_data=None):
-  """Runs a command and returns the output from that command.
+def _RunCommand(
+    command,
+    working_dir=None,
+    ignore_exit_code=False,
+    extra_env=None,
+    input_data=None,
+):
+    """Runs a command and returns the output from that command.
 
     If the command fails (exit code != 0), the function will exit the process.
 
     Returns:
       A tuple containing the stdout and stderr outputs as strings.
     """
-  working_dir = working_dir or CHECKOUT_SRC_DIR
-  logging.debug('CMD: %s CWD: %s', ' '.join(command), working_dir)
-  env = os.environ.copy()
-  if extra_env:
-    assert all(isinstance(value, str) for value in extra_env.values())
-    logging.debug('extra env: %s', extra_env)
-    env.update(extra_env)
-  p = subprocess.Popen(command,
-                       stdin=subprocess.PIPE,
-                       stdout=subprocess.PIPE,
-                       stderr=subprocess.PIPE,
-                       env=env,
-                       cwd=working_dir,
-                       universal_newlines=True)
-  std_output, err_output = p.communicate(input_data)
-  p.stdout.close()
-  p.stderr.close()
-  if not ignore_exit_code and p.returncode != 0:
-    logging.error('Command failed: %s\n'
-                  'stdout:\n%s\n'
-                  'stderr:\n%s\n', ' '.join(command), std_output, err_output)
-    sys.exit(p.returncode)
-  return std_output, err_output
+    working_dir = working_dir or CHECKOUT_ROOT_DIR
+    logging.debug('CMD: %s CWD: %s', ' '.join(command), working_dir)
+    env = os.environ.copy()
+    if extra_env:
+        assert all(isinstance(value, str) for value in extra_env.values())
+        logging.debug('extra env: %s', extra_env)
+        env.update(extra_env)
+    p = subprocess.Popen(
+        command,
+        stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        env=env,
+        cwd=working_dir,
+        universal_newlines=True,
+    )
+    std_output, err_output = p.communicate(input_data)
+    p.stdout.close()
+    p.stderr.close()
+    if not ignore_exit_code and p.returncode != 0:
+        logging.error(
+            'Command failed: %s\nstdout:\n%s\nstderr:\n%s\n',
+            ' '.join(command),
+            std_output,
+            err_output,
+        )
+        sys.exit(p.returncode)
+    return std_output, err_output
 
 
 def _GetBranches():
-  """Returns a tuple of active,branches.
+    """Returns a tuple of active,branches.
 
     The 'active' is the name of the currently active branch and 'branches' is a
     list of all branches.
     """
-  lines = _RunCommand(['git', 'branch'])[0].split('\n')
-  branches = []
-  active = ''
-  for line in lines:
-    if '*' in line:
-      # The assumption is that the first char will always be the '*'.
-      active = line[1:].strip()
-      branches.append(active)
-    else:
-      branch = line.strip()
-      if branch:
-        branches.append(branch)
-  return active, branches
+    lines = _RunCommand(['git', 'branch'])[0].split('\n')
+    branches = []
+    active = ''
+    for line in lines:
+        if '*' in line:
+            # The assumption is that the first char will always be the '*'.
+            active = line[1:].strip()
+            branches.append(active)
+        else:
+            branch = line.strip()
+            if branch:
+                branches.append(branch)
+    return active, branches
 
 
 def _ReadGitilesContent(url):
-  # Download and decode BASE64 content until
-  # https://code.google.com/p/gitiles/issues/detail?id=7 is fixed.
-  base64_content = ReadUrlContent(url + '?format=TEXT')
-  return base64.b64decode(base64_content[0]).decode('utf-8')
+    # Download and decode BASE64 content until
+    # https://code.google.com/p/gitiles/issues/detail?id=7 is fixed.
+    base64_content = ReadUrlContent(url + '?format=TEXT')
+    return base64.b64decode(base64_content[0]).decode('utf-8')
 
 
 def ReadRemoteCrFile(path_below_src, revision):
-  """Reads a remote Chromium file of a specific revision.
+    """Reads a remote Chromium file of a specific revision.
 
     Args:
       path_below_src: A path to the target file relative to src dir.
       revision: Revision to read.
+
     Returns:
       A string with file content.
     """
-  return _ReadGitilesContent(CHROMIUM_FILE_TEMPLATE %
-                             (revision, path_below_src))
+    return _ReadGitilesContent(
+        CHROMIUM_FILE_TEMPLATE % (revision, path_below_src)
+    )
 
 
 def ReadRemoteCrCommit(revision):
-  """Reads a remote Chromium commit message. Returns a string."""
-  return _ReadGitilesContent(CHROMIUM_COMMIT_TEMPLATE % revision)
+    """Reads a remote Chromium commit message. Returns a string."""
+    return _ReadGitilesContent(CHROMIUM_COMMIT_TEMPLATE % revision)
 
 
 def ReadUrlContent(url):
-  """Connect to a remote host and read the contents.
+    """Connect to a remote host and read the contents.
 
     Args:
       url: URL to connect to.
+
     Returns:
       A list of lines.
     """
-  conn = urllib.request.urlopen(url)
-  try:
-    return conn.readlines()
-  except IOError as e:
-    logging.exception('Error connecting to %s. Error: %s', url, e)
-    raise
-  finally:
-    conn.close()
+    conn = urllib.request.urlopen(url)
+    try:
+        return conn.readlines()
+    except IOError as e:
+        logging.exception('Error connecting to %s. Error: %s', url, e)
+        raise
+    finally:
+        conn.close()
 
 
 def GetMatchingDepsEntries(depsentry_dict, dir_path):
-  """Gets all deps entries matching the provided path.
+    """Gets all deps entries matching the provided path.
 
     This list may contain more than one DepsEntry object.
     Example: dir_path='src/testing' would give results containing both
@@ -261,94 +281,104 @@
     Returns:
       A list of DepsEntry objects.
     """
-  result = []
-  for path, depsentry in depsentry_dict.items():
-    if path == dir_path:
-      result.append(depsentry)
-    else:
-      parts = path.split('/')
-      if all(part == parts[i] for i, part in enumerate(dir_path.split('/'))):
-        result.append(depsentry)
-  return result
+    result = []
+    for path, depsentry in depsentry_dict.items():
+        if path == dir_path:
+            result.append(depsentry)
+        else:
+            parts = path.split('/')
+            if all(
+                part == parts[i] for i, part in enumerate(dir_path.split('/'))
+            ):
+                result.append(depsentry)
+    return result
 
 
 def BuildDepsentryDict(deps_dict):
-  """Builds a dict of paths to DepsEntry objects from a raw deps dict."""
-  result = {}
+    """Builds a dict of paths to DepsEntry objects from a raw deps dict."""
+    result = {}
 
-  def AddDepsEntries(deps_subdict):
-    for path, dep in deps_subdict.items():
-      if path in result:
-        continue
-      if not isinstance(dep, dict):
-        dep = {'url': dep}
-      if dep.get('dep_type') == 'cipd':
-        result[path] = CipdDepsEntry(path, dep['packages'])
-      else:
-        if '@' not in dep['url']:
-          continue
-        url, revision = dep['url'].split('@')
-        result[path] = DepsEntry(path, url, revision)
+    def AddDepsEntries(deps_subdict):
+        for path, dep in deps_subdict.items():
+            if path in result:
+                continue
+            if not isinstance(dep, dict):
+                dep = {'url': dep}
+            if dep.get('dep_type') == 'cipd':
+                result[path] = CipdDepsEntry(path, dep['packages'])
+            elif dep.get('dep_type') == 'gcs':
+                result[path] = GcsDepsEntry(path, dep['bucket'],
+                                            dep['objects'])
+            else:
+                if '@' not in dep['url']:
+                    url, revision = dep['url'], 'HEAD'
+                else:
+                    url, revision = dep['url'].split('@')
+                result[path] = DepsEntry(path, url, revision)
 
-  def AddVersionEntry(vars_subdict):
-    for key, value in vars_subdict.items():
-      if key in result:
-        continue
-      if not key.endswith('_version'):
-        continue
-      key = re.sub('_version$', '', key)
-      result[key] = VersionEntry(value)
+    def AddVersionEntry(vars_subdict):
+        for key, value in vars_subdict.items():
+            if key in result:
+                continue
+            if not key.endswith('_version'):
+                continue
+            key = re.sub('_version$', '', key)
+            result[key] = VersionEntry(value)
 
-  AddDepsEntries(deps_dict['deps'])
-  for deps_os in ['win', 'mac', 'unix', 'android', 'ios', 'unix']:
-    AddDepsEntries(deps_dict.get('deps_os', {}).get(deps_os, {}))
-  AddVersionEntry(deps_dict.get('vars', {}))
-  return result
+    AddDepsEntries(deps_dict['deps'])
+    for deps_os in ['win', 'mac', 'unix', 'android', 'ios', 'unix']:
+        AddDepsEntries(deps_dict.get('deps_os', {}).get(deps_os, {}))
+    AddVersionEntry(deps_dict.get('vars', {}))
+    return result
 
 
 def _FindChangedCipdPackages(path, old_pkgs, new_pkgs):
-  old_pkgs_names = {p['package'] for p in old_pkgs}
-  new_pkgs_names = {p['package'] for p in new_pkgs}
-  pkgs_equal = (old_pkgs_names == new_pkgs_names)
-  added_pkgs = [p for p in new_pkgs_names if p not in old_pkgs_names]
-  removed_pkgs = [p for p in old_pkgs_names if p not in new_pkgs_names]
+    old_pkgs_names = {p['package'] for p in old_pkgs}
+    new_pkgs_names = {p['package'] for p in new_pkgs}
+    pkgs_equal = old_pkgs_names == new_pkgs_names
+    added_pkgs = [p for p in new_pkgs_names if p not in old_pkgs_names]
+    removed_pkgs = [p for p in old_pkgs_names if p not in new_pkgs_names]
 
-  assert pkgs_equal, ('Old: %s\n New: %s.\nYou need to do a manual roll '
-                      'and remove/add entries in DEPS so the old and new '
-                      'list match.\nMost likely, you should add \"%s\" and '
-                      'remove \"%s\"' %
-                      (old_pkgs, new_pkgs, added_pkgs, removed_pkgs))
+    assert pkgs_equal, (
+        'Old: %s\n New: %s.\nYou need to do a manual roll '
+        'and remove/add entries in DEPS so the old and new '
+        'list match.\nMost likely, you should add "%s" and '
+        'remove "%s"' % (old_pkgs, new_pkgs, added_pkgs, removed_pkgs)
+    )
 
-  for old_pkg in old_pkgs:
-    for new_pkg in new_pkgs:
-      old_version = old_pkg['version']
-      new_version = new_pkg['version']
-      if (old_pkg['package'] == new_pkg['package']
-          and old_version != new_version):
-        logging.debug('Roll dependency %s to %s', path, new_version)
-        yield ChangedCipdPackage(path, old_pkg['package'], old_version,
-                                 new_version)
+    for old_pkg in old_pkgs:
+        for new_pkg in new_pkgs:
+            old_version = old_pkg['version']
+            new_version = new_pkg['version']
+            if (
+                old_pkg['package'] == new_pkg['package']
+                and old_version != new_version
+            ):
+                logging.debug('Roll dependency %s to %s', path, new_version)
+                yield ChangedCipdPackage(
+                    path, old_pkg['package'], old_version, new_version
+                )
 
 
 def _FindChangedVars(name, old_version, new_version):
-  if old_version != new_version:
-    logging.debug('Roll dependency %s to %s', name, new_version)
-    yield ChangedVersionEntry(name, old_version, new_version)
+    if old_version != new_version:
+        logging.debug('Roll dependency %s to %s', name, new_version)
+        yield ChangedVersionEntry(name, old_version, new_version)
 
 
 def _FindNewDeps(old, new):
-  """ Gather dependencies only in `new` and return corresponding paths. """
-  old_entries = set(BuildDepsentryDict(old))
-  new_entries = set(BuildDepsentryDict(new))
-  return [
-      path for path in new_entries - old_entries
-      if path not in DONT_AUTOROLL_THESE
-  ]
+    """Gather dependencies only in `new` and return corresponding paths."""
+    old_entries = set(BuildDepsentryDict(old))
+    new_entries = set(BuildDepsentryDict(new))
+    return [
+        path
+        for path in new_entries - old_entries
+        if path not in DONT_AUTOROLL_THESE
+    ]
 
 
 def FindAddedDeps(libyuv_deps, new_cr_deps):
-  """
-    Calculate new deps entries of interest.
+    """Calculate new deps entries of interest.
 
     Ideally, that would mean: only appearing in chromium DEPS
     but transitively used in LibYUV.
@@ -368,19 +398,18 @@
         A list of paths added dependencies sitting in `ANDROID_DEPS_PATH`.
         A list of paths for other added dependencies.
     """
-  all_added_deps = _FindNewDeps(libyuv_deps, new_cr_deps)
-  generated_android_deps = [
-      path for path in all_added_deps if path.startswith(ANDROID_DEPS_PATH)
-  ]
-  other_deps = [
-      path for path in all_added_deps if path not in generated_android_deps
-  ]
-  return generated_android_deps, other_deps
+    all_added_deps = _FindNewDeps(libyuv_deps, new_cr_deps)
+    generated_android_deps = [
+        path for path in all_added_deps if path.startswith(ANDROID_DEPS_PATH)
+    ]
+    other_deps = [
+        path for path in all_added_deps if path not in generated_android_deps
+    ]
+    return generated_android_deps, other_deps
 
 
 def FindRemovedDeps(libyuv_deps, new_cr_deps):
-  """
-    Calculate obsolete deps entries.
+    """Calculate obsolete deps entries.
 
     Ideally, that would mean: no more appearing in chromium DEPS
     and not used in LibYUV.
@@ -402,20 +431,24 @@
         A list of paths of dependencies removed from `ANDROID_DEPS_PATH`.
         A list of paths of unexpected disappearing dependencies.
     """
-  all_removed_deps = _FindNewDeps(new_cr_deps, libyuv_deps)
-  generated_android_deps = sorted(
-      [path for path in all_removed_deps if path.startswith(ANDROID_DEPS_PATH)])
-  # Webrtc-only dependencies are handled in CalculateChangedDeps.
-  other_deps = sorted([
-      path for path in all_removed_deps
-      if path not in generated_android_deps and path not in LIBYUV_ONLY_DEPS
-  ])
-  return generated_android_deps, other_deps
+    all_removed_deps = _FindNewDeps(new_cr_deps, libyuv_deps)
+    generated_android_deps = sorted([
+        path for path in all_removed_deps if path.startswith(ANDROID_DEPS_PATH)
+    ])
+    # Webrtc-only dependencies are handled in CalculateChangedDeps.
+    other_deps = sorted([
+        path
+        for path in all_removed_deps
+        if path not in generated_android_deps and path not in LIBYUV_ONLY_DEPS
+    ])
+    return generated_android_deps, other_deps
 
 
 def CalculateChangedDeps(libyuv_deps, new_cr_deps):
-  """
-    Calculate changed deps entries based on entries defined in the LibYUV DEPS
+    """Calculate changed deps entries based on entries defined in the LibYUV
+
+    DEPS
+
     file:
      - If a shared dependency with the Chromium DEPS file: roll it to the same
        revision as Chromium (i.e. entry in the new_cr_deps dict)
@@ -428,254 +461,298 @@
     Returns:
       A list of ChangedDep objects representing the changed deps.
     """
-  result = []
-  libyuv_entries = BuildDepsentryDict(libyuv_deps)
-  new_cr_entries = BuildDepsentryDict(new_cr_deps)
-  for path, libyuv_deps_entry in libyuv_entries.items():
-    if path in DONT_AUTOROLL_THESE:
-      continue
-    cr_deps_entry = new_cr_entries.get(path)
-    if cr_deps_entry:
-      assert type(cr_deps_entry) is type(libyuv_deps_entry)
+    result = []
+    libyuv_entries = BuildDepsentryDict(libyuv_deps)
+    new_cr_entries = BuildDepsentryDict(new_cr_deps)
+    for path, libyuv_deps_entry in libyuv_entries.items():
+        if path in DONT_AUTOROLL_THESE:
+            continue
+        cr_deps_entry = new_cr_entries.get(path)
+        if cr_deps_entry:
+            assert type(cr_deps_entry) is type(libyuv_deps_entry)
 
-      if isinstance(cr_deps_entry, CipdDepsEntry):
-        result.extend(
-            _FindChangedCipdPackages(path, libyuv_deps_entry.packages,
-                                     cr_deps_entry.packages))
-        continue
+            if isinstance(cr_deps_entry, CipdDepsEntry):
+                result.extend(
+                    _FindChangedCipdPackages(path, libyuv_deps_entry.packages,
+                                             cr_deps_entry.packages))
+                continue
 
-      if isinstance(cr_deps_entry, VersionEntry):
-        result.extend(
-            _FindChangedVars(path, libyuv_deps_entry.version,
-                             cr_deps_entry.version))
-        continue
+            if isinstance(cr_deps_entry, GcsDepsEntry):
+                result.extend(
+                    _FindChangedVars(
+                        path, ','.join(x['object_name']
+                                       for x in libyuv_deps_entry.objects),
+                        ','.join(x['object_name']
+                                 for x in cr_deps_entry.objects)))
+                continue
 
-      # Use the revision from Chromium's DEPS file.
-      new_rev = cr_deps_entry.revision
-      assert libyuv_deps_entry.url == cr_deps_entry.url, (
-          'LibYUV DEPS entry %s has a different URL %s than Chromium %s.' %
-          (path, libyuv_deps_entry.url, cr_deps_entry.url))
-    else:
-      if isinstance(libyuv_deps_entry, DepsEntry):
-        # Use the HEAD of the deps repo.
-        stdout, _ = _RunCommand(
-            ['git', 'ls-remote', libyuv_deps_entry.url, 'HEAD'])
-        new_rev = stdout.strip().split('\t')[0]
-      else:
-        # The dependency has been removed from chromium.
-        # This is handled by FindRemovedDeps.
-        continue
+            if isinstance(cr_deps_entry, VersionEntry):
+                result.extend(
+                    _FindChangedVars(
+                        path, libyuv_deps_entry.version, cr_deps_entry.version
+                    )
+                )
+                continue
 
-    # Check if an update is necessary.
-    if libyuv_deps_entry.revision != new_rev:
-      logging.debug('Roll dependency %s to %s', path, new_rev)
-      result.append(
-          ChangedDep(path, libyuv_deps_entry.url, libyuv_deps_entry.revision,
-                     new_rev))
-  return sorted(result)
+            # Use the revision from Chromium's DEPS file.
+            new_rev = cr_deps_entry.revision
+            assert libyuv_deps_entry.url == cr_deps_entry.url, (
+                'LibYUV DEPS entry %s has a different URL %s than Chromium %s.'
+                % (
+                    path,
+                    libyuv_deps_entry.url,
+                    cr_deps_entry.url,
+                )
+            )
+        else:
+            if isinstance(libyuv_deps_entry, DepsEntry):
+                # Use the HEAD of the deps repo.
+                stdout, _ = _RunCommand(
+                    ['git', 'ls-remote', libyuv_deps_entry.url, 'HEAD']
+                )
+                new_rev = stdout.strip().split('\t')[0]
+            else:
+                # The dependency has been removed from chromium.
+                # This is handled by FindRemovedDeps.
+                continue
+
+        # Check if an update is necessary.
+        if libyuv_deps_entry.revision != new_rev:
+            logging.debug('Roll dependency %s to %s', path, new_rev)
+            result.append(
+                ChangedDep(
+                    path,
+                    libyuv_deps_entry.url,
+                    libyuv_deps_entry.revision,
+                    new_rev,
+                )
+            )
+    return sorted(result)
 
 
 def CalculateChangedClang(new_cr_rev):
 
-  def GetClangRev(lines):
-    for line in lines:
-      match = CLANG_REVISION_RE.match(line)
-      if match:
-        return match.group(1)
-    raise RollError('Could not parse Clang revision!')
+    def GetClangRev(lines):
+        for line in lines:
+            match = CLANG_REVISION_RE.match(line)
+            if match:
+                return match.group(1)
+        raise RollError('Could not parse Clang revision!')
 
-  with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH, 'r') as f:
-    current_lines = f.readlines()
-  current_rev = GetClangRev(current_lines)
+    with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH, 'r') as f:
+        current_lines = f.readlines()
+    current_rev = GetClangRev(current_lines)
 
-  new_clang_update_py = ReadRemoteCrFile(CLANG_UPDATE_SCRIPT_URL_PATH,
-                                         new_cr_rev).splitlines()
-  new_rev = GetClangRev(new_clang_update_py)
-  return ChangedDep(CLANG_UPDATE_SCRIPT_LOCAL_PATH, None, current_rev, new_rev)
+    new_clang_update_py = ReadRemoteCrFile(
+        CLANG_UPDATE_SCRIPT_URL_PATH, new_cr_rev
+    ).splitlines()
+    new_rev = GetClangRev(new_clang_update_py)
+    return ChangedDep(
+        CLANG_UPDATE_SCRIPT_LOCAL_PATH, None, current_rev, new_rev
+    )
 
 
 def GenerateCommitMessage(
-        rev_update,
-        current_commit_pos,
-        new_commit_pos,
-        changed_deps_list,
-        added_deps_paths=None,
-        removed_deps_paths=None,
-        clang_change=None,
+    rev_update,
+    current_commit_pos,
+    new_commit_pos,
+    changed_deps_list,
+    added_deps_paths=None,
+    removed_deps_paths=None,
+    clang_change=None,
 ):
-  current_cr_rev = rev_update.current_chromium_rev[0:10]
-  new_cr_rev = rev_update.new_chromium_rev[0:10]
-  rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev)
-  git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos)
+    current_cr_rev = rev_update.current_chromium_rev[0:10]
+    new_cr_rev = rev_update.new_chromium_rev[0:10]
+    rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev)
+    git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos)
 
-  commit_msg = [
-      'Roll chromium_revision %s (%s)\n' % (rev_interval, git_number_interval),
-      'Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval),
-      'Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE % rev_interval)
-  ]
+    commit_msg = [
+        'Roll chromium_revision %s (%s)\n'
+        % (rev_interval, git_number_interval),
+        'Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval),
+        'Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE % rev_interval),
+    ]
 
-  def Section(adjective, deps):
-    noun = 'dependency' if len(deps) == 1 else 'dependencies'
-    commit_msg.append('%s %s' % (adjective, noun))
+    def Section(adjective, deps):
+        noun = 'dependency' if len(deps) == 1 else 'dependencies'
+        commit_msg.append('%s %s' % (adjective, noun))
 
-  if changed_deps_list:
-    Section('Changed', changed_deps_list)
+    if changed_deps_list:
+        Section('Changed', changed_deps_list)
 
-    for c in changed_deps_list:
-      if isinstance(c, ChangedCipdPackage):
-        commit_msg.append('* %s: %s..%s' %
-                          (c.path, c.current_version, c.new_version))
-      elif isinstance(c, ChangedVersionEntry):
-        commit_msg.append('* %s_vesion: %s..%s' %
-                          (c.path, c.current_version, c.new_version))
-      else:
-        commit_msg.append('* %s: %s/+log/%s..%s' %
-                          (c.path, c.url, c.current_rev[0:10], c.new_rev[0:10]))
+        for c in changed_deps_list:
+            if isinstance(c, ChangedCipdPackage):
+                commit_msg.append(
+                    '* %s: %s..%s' % (c.path, c.current_version, c.new_version)
+                )
+            elif isinstance(c, ChangedVersionEntry):
+                commit_msg.append(
+                    '* %s_vesion: %s..%s'
+                    % (c.path, c.current_version, c.new_version)
+                )
+            else:
+                commit_msg.append(
+                    '* %s: %s/+log/%s..%s'
+                    % (c.path, c.url, c.current_rev[0:10], c.new_rev[0:10])
+                )
 
-  if added_deps_paths:
-    Section('Added', added_deps_paths)
-    commit_msg.extend('* %s' % p for p in added_deps_paths)
+    if added_deps_paths:
+        Section('Added', added_deps_paths)
+        commit_msg.extend('* %s' % p for p in added_deps_paths)
 
-  if removed_deps_paths:
-    Section('Removed', removed_deps_paths)
-    commit_msg.extend('* %s' % p for p in removed_deps_paths)
+    if removed_deps_paths:
+        Section('Removed', removed_deps_paths)
+        commit_msg.extend('* %s' % p for p in removed_deps_paths)
 
-  if any([changed_deps_list, added_deps_paths, removed_deps_paths]):
-    change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS')
-    commit_msg.append('DEPS diff: %s\n' % change_url)
-  else:
-    commit_msg.append('No dependencies changed.')
+    if any([changed_deps_list, added_deps_paths, removed_deps_paths]):
+        change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS')
+        commit_msg.append('DEPS diff: %s\n' % change_url)
+    else:
+        commit_msg.append('No dependencies changed.')
 
-  if clang_change and clang_change.current_rev != clang_change.new_rev:
-    commit_msg.append('Clang version changed %s:%s' %
-                      (clang_change.current_rev, clang_change.new_rev))
-    change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval,
-                                           CLANG_UPDATE_SCRIPT_URL_PATH)
-    commit_msg.append('Details: %s\n' % change_url)
-  else:
-    commit_msg.append('No update to Clang.\n')
+    if clang_change and clang_change.current_rev != clang_change.new_rev:
+        commit_msg.append(
+            'Clang version changed %s:%s'
+            % (clang_change.current_rev, clang_change.new_rev)
+        )
+        change_url = CHROMIUM_FILE_TEMPLATE % (
+            rev_interval,
+            CLANG_UPDATE_SCRIPT_URL_PATH,
+        )
+        commit_msg.append('Details: %s\n' % change_url)
+    else:
+        commit_msg.append('No update to Clang.\n')
 
-  commit_msg.append('BUG=None')
-  return '\n'.join(commit_msg)
+    commit_msg.append('BUG=None')
+    return '\n'.join(commit_msg)
 
 
 def UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content):
-  """Update the DEPS file with the new revision."""
+    """Update the DEPS file with the new revision."""
 
-  with open(deps_filename, 'rb') as deps_file:
-    deps_content = deps_file.read().decode('utf-8')
+    with open(deps_filename, 'rb') as deps_file:
+        deps_content = deps_file.read().decode('utf-8')
 
-  # Update the chromium_revision variable.
-  deps_content = deps_content.replace(rev_update.current_chromium_rev,
-                                      rev_update.new_chromium_rev)
+    # Update the chromium_revision variable.
+    deps_content = deps_content.replace(
+        rev_update.current_chromium_rev, rev_update.new_chromium_rev
+    )
 
-  # Add and remove dependencies. For now: only generated android deps.
-  # Since gclient cannot add or remove deps, we on the fact that
-  # these android deps are located in one place we can copy/paste.
-  deps_re = re.compile(ANDROID_DEPS_START + '.*' + ANDROID_DEPS_END, re.DOTALL)
-  new_deps = deps_re.search(new_cr_content)
-  old_deps = deps_re.search(deps_content)
-  if not new_deps or not old_deps:
-    faulty = 'Chromium' if not new_deps else 'LibYUV'
-    raise RollError('Was expecting to find "%s" and "%s"\n'
-                    'in %s DEPS' %
-                    (ANDROID_DEPS_START, ANDROID_DEPS_END, faulty))
-  deps_content = deps_re.sub(new_deps.group(0), deps_content)
+    # Add and remove dependencies. For now: only generated android deps.
+    # Since gclient cannot add or remove deps, we on the fact that
+    # these android deps are located in one place we can copy/paste.
+    deps_re = re.compile(
+        ANDROID_DEPS_START + '.*' + ANDROID_DEPS_END, re.DOTALL
+    )
+    new_deps = deps_re.search(new_cr_content)
+    old_deps = deps_re.search(deps_content)
+    if not new_deps or not old_deps:
+        faulty = 'Chromium' if not new_deps else 'LibYUV'
+        raise RollError(
+            'Was expecting to find "%s" and "%s"\nin %s DEPS'
+            % (ANDROID_DEPS_START, ANDROID_DEPS_END, faulty)
+        )
+    deps_content = deps_re.sub(new_deps.group(0), deps_content)
 
-  for dep in changed_deps:
-    if isinstance(dep, ChangedVersionEntry):
-      deps_content = deps_content.replace(dep.current_version, dep.new_version)
+    for dep in changed_deps:
+        if isinstance(dep, ChangedVersionEntry):
+            deps_content = deps_content.replace(
+                dep.current_version, dep.new_version
+            )
 
-  with open(deps_filename, 'wb') as deps_file:
-    deps_file.write(deps_content.encode('utf-8'))
+    with open(deps_filename, 'wb') as deps_file:
+        deps_file.write(deps_content.encode('utf-8'))
 
-  # Update each individual DEPS entry.
-  for dep in changed_deps:
-    # ChangedVersionEntry types are already been processed.
-    if isinstance(dep, ChangedVersionEntry):
-      continue
-    local_dep_dir = os.path.join(CHECKOUT_ROOT_DIR, dep.path)
-    if not os.path.isdir(local_dep_dir):
-      raise RollError(
-          'Cannot find local directory %s. Either run\n'
-          'gclient sync --deps=all\n'
-          'or make sure the .gclient file for your solution contains all '
-          'platforms in the target_os list, i.e.\n'
-          'target_os = ["android", "unix", "mac", "ios", "win"];\n'
-          'Then run "gclient sync" again.' % local_dep_dir)
-    if isinstance(dep, ChangedCipdPackage):
-      package = dep.package.format()  # Eliminate double curly brackets
-      update = '%s:%s@%s' % (dep.path, package, dep.new_version)
-    else:
-      update = '%s@%s' % (dep.path, dep.new_rev)
-    _RunCommand(['gclient', 'setdep', '--revision', update],
-                working_dir=CHECKOUT_SRC_DIR)
+    # Update each individual DEPS entry.
+    for dep in changed_deps:
+        # ChangedVersionEntry types are already been processed.
+        if isinstance(dep, ChangedVersionEntry):
+            continue
+        local_dep_dir = os.path.join(GCLIENT_ROOT_DIR, dep.path)
+        if not os.path.isdir(local_dep_dir):
+            raise RollError(
+                'Cannot find local directory %s. Either run\n'
+                'gclient sync --deps=all\n'
+                'or make sure the .gclient file for your solution contains '
+                'all platforms in the target_os list, i.e.\n'
+                'target_os = ["android", "unix", "mac", "ios", "win"];\n'
+                'Then run "gclient sync" again.' % local_dep_dir
+            )
+        if isinstance(dep, ChangedCipdPackage):
+            package = dep.package.format()  # Eliminate double curly brackets
+            update = '%s:%s@%s' % (dep.path, package, dep.new_version)
+        else:
+            update = '%s@%s' % (dep.path, dep.new_rev)
+        _RunCommand(
+            ['gclient', 'setdep', '--revision', update],
+            working_dir=CHECKOUT_ROOT_DIR,
+        )
 
 
 def _IsTreeClean():
-  stdout, _ = _RunCommand(['git', 'status', '--porcelain'])
-  if len(stdout) == 0:
-    return True
+    stdout, _ = _RunCommand(['git', 'status', '--porcelain'])
+    if len(stdout) == 0:
+        return True
 
-  logging.error('Dirty/unversioned files:\n%s', stdout)
-  return False
+    logging.error('Dirty/unversioned files:\n%s', stdout)
+    return False
 
 
 def _EnsureUpdatedMainBranch(dry_run):
-  current_branch = _RunCommand(['git', 'rev-parse', '--abbrev-ref',
-                                'HEAD'])[0].splitlines()[0]
-  if current_branch != 'main':
-    logging.error('Please checkout the main branch and re-run this script.')
-    if not dry_run:
-      sys.exit(-1)
+    current_branch = _RunCommand(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])[
+        0
+    ].splitlines()[0]
+    if current_branch != 'main':
+        logging.error('Please checkout the main branch and re-run this script.')  # pylint: disable=line-too-long
+        if not dry_run:
+            sys.exit(-1)
 
-  logging.info('Updating main branch...')
-  _RunCommand(['git', 'pull'])
+    logging.info('Updating main branch...')
+    _RunCommand(['git', 'pull'])
 
 
 def _CreateRollBranch(dry_run):
-  logging.info('Creating roll branch: %s', ROLL_BRANCH_NAME)
-  if not dry_run:
-    _RunCommand(['git', 'checkout', '-b', ROLL_BRANCH_NAME])
+    logging.info('Creating roll branch: %s', ROLL_BRANCH_NAME)
+    if not dry_run:
+        _RunCommand(['git', 'checkout', '-b', ROLL_BRANCH_NAME])
 
 
 def _RemovePreviousRollBranch(dry_run):
-  active_branch, branches = _GetBranches()
-  if active_branch == ROLL_BRANCH_NAME:
-    active_branch = 'main'
-  if ROLL_BRANCH_NAME in branches:
-    logging.info('Removing previous roll branch (%s)', ROLL_BRANCH_NAME)
-    if not dry_run:
-      _RunCommand(['git', 'checkout', active_branch])
-      _RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME])
+    active_branch, branches = _GetBranches()
+    if active_branch == ROLL_BRANCH_NAME:
+        active_branch = 'main'
+    if ROLL_BRANCH_NAME in branches:
+        logging.info('Removing previous roll branch (%s)', ROLL_BRANCH_NAME)
+        if not dry_run:
+            _RunCommand(['git', 'checkout', active_branch])
+            _RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME])
 
 
 def _LocalCommit(commit_msg, dry_run):
-  logging.info('Committing changes locally.')
-  if not dry_run:
-    _RunCommand(['git', 'add', '--update', '.'])
-    _RunCommand(['git', 'commit', '-m', commit_msg])
+    logging.info('Committing changes locally.')
+    if not dry_run:
+        _RunCommand(['git', 'add', '--update', '.'])
+        _RunCommand(['git', 'commit', '-m', commit_msg])
 
 
 def ChooseCQMode(skip_cq, cq_over, current_commit_pos, new_commit_pos):
-  if skip_cq:
-    return 0
-  if (new_commit_pos - current_commit_pos) < cq_over:
-    return 1
-  return 2
+    if skip_cq:
+        return 0
+    if (new_commit_pos - current_commit_pos) < cq_over:
+        return 1
+    return 2
 
 
 def _GetCcRecipients(changed_deps_list):
-  """Returns a list of emails to notify based on the changed deps list.
-    """
-  cc_recipients = []
-  for c in changed_deps_list:
-    pass
-  return cc_recipients
+    """Returns a list of emails to notify based on the changed deps list."""
+    cc_recipients = []
+    for _ in changed_deps_list:
+        pass
+    return cc_recipients
 
 
 def _UploadCL(commit_queue_mode, add_cc=None):
-  """Upload the committed changes as a changelist to Gerrit.
+    """Upload the committed changes as a changelist to Gerrit.
 
     commit_queue_mode:
      - 2: Submit to commit queue.
@@ -684,139 +761,171 @@
 
     add_cc: A list of email addresses to add as CC recipients.
     """
-  cc_recipients = []
-  if add_cc:
-    cc_recipients.extend(add_cc)
-  cmd = ['git', 'cl', 'upload', '--force', '--bypass-hooks']
-  if commit_queue_mode >= 2:
-    logging.info('Sending the CL to the CQ...')
-    cmd.extend(['-o', 'label=Bot-Commit+1'])
-    cmd.extend(['-o', 'label=Commit-Queue+2'])
-    cmd.extend(['--send-mail', '--cc', ','.join(cc_recipients)])
-  elif commit_queue_mode >= 1:
-    logging.info('Starting CQ dry run...')
-    cmd.extend(['-o', 'label=Commit-Queue+1'])
-  extra_env = {
-      'EDITOR': 'true',
-      'SKIP_GCE_AUTH_FOR_GIT': '1',
-  }
-  stdout, stderr = _RunCommand(cmd, extra_env=extra_env)
-  logging.debug('Output from "git cl upload":\nstdout:\n%s\n\nstderr:\n%s',
-                stdout, stderr)
+    cc_recipients = []
+    if add_cc:
+        cc_recipients.extend(add_cc)
+    cmd = ['git', 'cl', 'upload', '--force', '--bypass-hooks']
+    if commit_queue_mode >= 2:
+        logging.info('Sending the CL to the CQ...')
+        cmd.extend(['-o', 'label=Bot-Commit+1'])
+        cmd.extend(['-o', 'label=Commit-Queue+2'])
+        cmd.extend(['--send-mail', '--cc', ','.join(cc_recipients)])
+    elif commit_queue_mode >= 1:
+        logging.info('Starting CQ dry run...')
+        cmd.extend(['-o', 'label=Commit-Queue+1'])
+    extra_env = {
+        'EDITOR': 'true',
+        'SKIP_GCE_AUTH_FOR_GIT': '1',
+    }
+    stdout, stderr = _RunCommand(cmd, extra_env=extra_env)
+    logging.debug(
+        'Output from "git cl upload":\nstdout:\n%s\n\nstderr:\n%s',
+        stdout,
+        stderr,
+    )
 
 
 def GetRollRevisionRanges(opts, libyuv_deps):
-  current_cr_rev = libyuv_deps['vars']['chromium_revision']
-  new_cr_rev = opts.revision
-  if not new_cr_rev:
-    stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD'])
-    head_rev = stdout.strip().split('\t')[0]
-    logging.info('No revision specified. Using HEAD: %s', head_rev)
-    new_cr_rev = head_rev
+    current_cr_rev = libyuv_deps['vars']['chromium_revision']
+    new_cr_rev = opts.revision
+    if not new_cr_rev:
+        stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD'])
+        head_rev = stdout.strip().split('\t')[0]
+        logging.info('No revision specified. Using HEAD: %s', head_rev)
+        new_cr_rev = head_rev
 
-  return ChromiumRevisionUpdate(current_cr_rev, new_cr_rev)
+    return ChromiumRevisionUpdate(current_cr_rev, new_cr_rev)
 
 
 def main():
-  p = argparse.ArgumentParser()
-  p.add_argument('--clean',
-                 action='store_true',
-                 default=False,
-                 help='Removes any previous local roll branch.')
-  p.add_argument('-r',
-                 '--revision',
-                 help=('Chromium Git revision to roll to. Defaults to the '
-                       'Chromium HEAD revision if omitted.'))
-  p.add_argument('--dry-run',
-                 action='store_true',
-                 default=False,
-                 help=('Calculate changes and modify DEPS, but don\'t create '
-                       'any local branch, commit, upload CL or send any '
-                       'tryjobs.'))
-  p.add_argument('-i',
-                 '--ignore-unclean-workdir',
-                 action='store_true',
-                 default=False,
-                 help=('Ignore if the current branch is not main or if there '
-                       'are uncommitted changes (default: %(default)s).'))
-  grp = p.add_mutually_exclusive_group()
-  grp.add_argument('--skip-cq',
-                   action='store_true',
-                   default=False,
-                   help='Skip sending the CL to the CQ (default: %(default)s)')
-  grp.add_argument('--cq-over',
-                   type=int,
-                   default=1,
-                   help=('Commit queue dry run if the revision difference '
-                         'is below this number (default: %(default)s)'))
-  p.add_argument('-v',
-                 '--verbose',
-                 action='store_true',
-                 default=False,
-                 help='Be extra verbose in printing of log messages.')
-  opts = p.parse_args()
+    p = argparse.ArgumentParser()
+    p.add_argument(
+        '--clean',
+        action='store_true',
+        default=False,
+        help='Removes any previous local roll branch.',
+    )
+    p.add_argument(
+        '-r',
+        '--revision',
+        help=(
+            'Chromium Git revision to roll to. Defaults to the '
+            'Chromium HEAD revision if omitted.'
+        ),
+    )
+    p.add_argument(
+        '--dry-run',
+        action='store_true',
+        default=False,
+        help=(
+            "Calculate changes and modify DEPS, but don't create "
+            'any local branch, commit, upload CL or send any '
+            'tryjobs.'
+        ),
+    )
+    p.add_argument(
+        '-i',
+        '--ignore-unclean-workdir',
+        action='store_true',
+        default=False,
+        help=(
+            'Ignore if the current branch is not main or if there '
+            'are uncommitted changes (default: %(default)s).'
+        ),
+    )
+    grp = p.add_mutually_exclusive_group()
+    grp.add_argument(
+        '--skip-cq',
+        action='store_true',
+        default=False,
+        help='Skip sending the CL to the CQ (default: %(default)s)',
+    )
+    grp.add_argument(
+        '--cq-over',
+        type=int,
+        default=1,
+        help=(
+            'Commit queue dry run if the revision difference '
+            'is below this number (default: %(default)s)'
+        ),
+    )
+    p.add_argument(
+        '-v',
+        '--verbose',
+        action='store_true',
+        default=False,
+        help='Be extra verbose in printing of log messages.',
+    )
+    opts = p.parse_args()
 
-  if opts.verbose:
-    logging.basicConfig(level=logging.DEBUG)
-  else:
-    logging.basicConfig(level=logging.INFO)
+    if opts.verbose:
+        logging.basicConfig(level=logging.DEBUG)
+    else:
+        logging.basicConfig(level=logging.INFO)
 
-  if not opts.ignore_unclean_workdir and not _IsTreeClean():
-    logging.error('Please clean your local checkout first.')
-    return 1
+    if not opts.ignore_unclean_workdir and not _IsTreeClean():
+        logging.error('Please clean your local checkout first.')
+        return 1
 
-  if opts.clean:
-    _RemovePreviousRollBranch(opts.dry_run)
+    if opts.clean:
+        _RemovePreviousRollBranch(opts.dry_run)
 
-  if not opts.ignore_unclean_workdir:
-    _EnsureUpdatedMainBranch(opts.dry_run)
+    if not opts.ignore_unclean_workdir:
+        _EnsureUpdatedMainBranch(opts.dry_run)
 
-  deps_filename = os.path.join(CHECKOUT_SRC_DIR, 'DEPS')
-  libyuv_deps = ParseLocalDepsFile(deps_filename)
+    deps_filename = os.path.join(CHECKOUT_ROOT_DIR, 'DEPS')
+    libyuv_deps = ParseLocalDepsFile(deps_filename)
 
-  rev_update = GetRollRevisionRanges(opts, libyuv_deps)
+    rev_update = GetRollRevisionRanges(opts, libyuv_deps)
 
-  current_commit_pos = ParseCommitPosition(
-      ReadRemoteCrCommit(rev_update.current_chromium_rev))
-  new_commit_pos = ParseCommitPosition(
-      ReadRemoteCrCommit(rev_update.new_chromium_rev))
+    current_commit_pos = ParseCommitPosition(
+        ReadRemoteCrCommit(rev_update.current_chromium_rev)
+    )
+    new_commit_pos = ParseCommitPosition(
+        ReadRemoteCrCommit(rev_update.new_chromium_rev)
+    )
 
-  new_cr_content = ReadRemoteCrFile('DEPS', rev_update.new_chromium_rev)
-  new_cr_deps = ParseDepsDict(new_cr_content)
-  changed_deps = CalculateChangedDeps(libyuv_deps, new_cr_deps)
-  # Discard other deps, assumed to be chromium-only dependencies.
-  new_generated_android_deps, _ = FindAddedDeps(libyuv_deps, new_cr_deps)
-  removed_generated_android_deps, other_deps = FindRemovedDeps(
-      libyuv_deps, new_cr_deps)
-  if other_deps:
-    raise RollError('LibYUV DEPS entries are missing from Chromium: %s.\n'
-                    'Remove them or add them to either '
-                    'LIBYUV_ONLY_DEPS or DONT_AUTOROLL_THESE.' % other_deps)
-  clang_change = CalculateChangedClang(rev_update.new_chromium_rev)
-  commit_msg = GenerateCommitMessage(
-      rev_update,
-      current_commit_pos,
-      new_commit_pos,
-      changed_deps,
-      added_deps_paths=new_generated_android_deps,
-      removed_deps_paths=removed_generated_android_deps,
-      clang_change=clang_change)
-  logging.debug('Commit message:\n%s', commit_msg)
+    new_cr_content = ReadRemoteCrFile('DEPS', rev_update.new_chromium_rev)
+    new_cr_deps = ParseDepsDict(new_cr_content)
+    changed_deps = CalculateChangedDeps(libyuv_deps, new_cr_deps)
+    # Discard other deps, assumed to be chromium-only dependencies.
+    new_generated_android_deps, _ = FindAddedDeps(libyuv_deps, new_cr_deps)
+    removed_generated_android_deps, other_deps = FindRemovedDeps(
+        libyuv_deps, new_cr_deps
+    )
+    if other_deps:
+        raise RollError(
+            'LibYUV DEPS entries are missing from Chromium: %s.\n'
+            'Remove them or add them to either '
+            'LIBYUV_ONLY_DEPS or DONT_AUTOROLL_THESE.' % other_deps
+        )
+    clang_change = CalculateChangedClang(rev_update.new_chromium_rev)
+    commit_msg = GenerateCommitMessage(
+        rev_update,
+        current_commit_pos,
+        new_commit_pos,
+        changed_deps,
+        added_deps_paths=new_generated_android_deps,
+        removed_deps_paths=removed_generated_android_deps,
+        clang_change=clang_change,
+    )
+    logging.debug('Commit message:\n%s', commit_msg)
 
-  _CreateRollBranch(opts.dry_run)
-  if not opts.dry_run:
-    UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content)
-  if _IsTreeClean():
-    logging.info("No DEPS changes detected, skipping CL creation.")
-  else:
-    _LocalCommit(commit_msg, opts.dry_run)
-    commit_queue_mode = ChooseCQMode(opts.skip_cq, opts.cq_over,
-                                     current_commit_pos, new_commit_pos)
-    logging.info('Uploading CL...')
+    _CreateRollBranch(opts.dry_run)
     if not opts.dry_run:
-      _UploadCL(commit_queue_mode, _GetCcRecipients(changed_deps))
-  return 0
+        UpdateDepsFile(deps_filename, rev_update, changed_deps, new_cr_content)
+    if _IsTreeClean():
+        logging.info('No DEPS changes detected, skipping CL creation.')
+    else:
+        _LocalCommit(commit_msg, opts.dry_run)
+        commit_queue_mode = ChooseCQMode(
+            opts.skip_cq, opts.cq_over, current_commit_pos, new_commit_pos
+        )
+        logging.info('Uploading CL...')
+        if not opts.dry_run:
+            _UploadCL(commit_queue_mode, _GetCcRecipients(changed_deps))
+    return 0
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+    sys.exit(main())
diff --git a/tools_libyuv/autoroller/unittests/roll_deps_test.py b/tools_libyuv/autoroller/unittests/roll_deps_test.py
index af86bdd..bd38c94 100755
--- a/tools_libyuv/autoroller/unittests/roll_deps_test.py
+++ b/tools_libyuv/autoroller/unittests/roll_deps_test.py
@@ -16,23 +16,22 @@
 import unittest
 
 import roll_deps
-from roll_deps import CalculateChangedDeps, GetMatchingDepsEntries, \
-  ParseDepsDict, ParseLocalDepsFile, UpdateDepsFile
+from roll_deps import CalculateChangedDeps, GetMatchingDepsEntries, ParseDepsDict, ParseLocalDepsFile, UpdateDepsFile  # pylint: disable=line-too-long
 
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 PARENT_DIR = os.path.join(SCRIPT_DIR, os.pardir)
 sys.path.append(PARENT_DIR)
 
 TEST_DATA_VARS = {
-  'chromium_git': 'https://chromium.googlesource.com',
-  'chromium_revision': '1b9c098a08e40114e44b6c1ec33ddf95c40b901d',
+    'chromium_git': 'https://chromium.googlesource.com',
+    'chromium_revision': '1b9c098a08e40114e44b6c1ec33ddf95c40b901d',
 }
 
 DEPS_ENTRIES = {
-  'src/build': 'https://build.com',
-  'src/buildtools': 'https://buildtools.com',
-  'src/testing/gtest': 'https://gtest.com',
-  'src/testing/gmock': 'https://gmock.com',
+    'src/build': 'https://build.com',
+    'src/buildtools': 'https://buildtools.com',
+    'src/testing/gtest': 'https://gtest.com',
+    'src/testing/gmock': 'https://gmock.com',
 }
 
 BUILD_OLD_REV = '52f7afeca991d96d68cf0507e20dbdd5b845691f'
@@ -42,107 +41,124 @@
 
 
 class TestError(Exception):
-  pass
+    pass
 
 
-class FakeCmd():
-  def __init__(self):
-    self.expectations = []
+class FakeCmd:
 
-  def add_expectation(self, *args, **kwargs):
-    returns = kwargs.pop('_returns', None)
-    self.expectations.append((args, kwargs, returns))
+    def __init__(self):
+        self.expectations = []
 
-  def __call__(self, *args, **kwargs):
-    if not self.expectations:
-      raise TestError('Got unexpected\n%s\n%s' % (args, kwargs))
-    exp_args, exp_kwargs, exp_returns = self.expectations.pop(0)
-    if args != exp_args or kwargs != exp_kwargs:
-      message = 'Expected:\n  args: %s\n  kwargs: %s\n' % (exp_args, exp_kwargs)
-      message += 'Got:\n  args: %s\n  kwargs: %s\n' % (args, kwargs)
-      raise TestError(message)
-    return exp_returns
+    def add_expectation(self, *args, **kwargs):
+        returns = kwargs.pop('_returns', None)
+        self.expectations.append((args, kwargs, returns))
+
+    def __call__(self, *args, **kwargs):
+        if not self.expectations:
+            raise TestError('Got unexpected\n%s\n%s' % (args, kwargs))
+        exp_args, exp_kwargs, exp_returns = self.expectations.pop(0)
+        if args != exp_args or kwargs != exp_kwargs:
+            message = 'Expected:\n  args: %s\n  kwargs: %s\n' % (
+                exp_args,
+                exp_kwargs,
+            )
+            message += 'Got:\n  args: %s\n  kwargs: %s\n' % (args, kwargs)
+            raise TestError(message)
+        return exp_returns
 
 
 class TestRollChromiumRevision(unittest.TestCase):
-  def setUp(self):
-    self._output_dir = tempfile.mkdtemp()
-    for test_file in glob.glob(os.path.join(SCRIPT_DIR, 'testdata', '*')):
-      shutil.copy(test_file, self._output_dir)
-    self._libyuv_depsfile = os.path.join(self._output_dir, 'DEPS')
-    self._old_cr_depsfile = os.path.join(self._output_dir, 'DEPS.chromium.old')
-    self._new_cr_depsfile = os.path.join(self._output_dir, 'DEPS.chromium.new')
 
-    self.fake = FakeCmd()
-    self.old_RunCommand = getattr(roll_deps, '_RunCommand')
-    setattr(roll_deps, '_RunCommand', self.fake)
+    def setUp(self):
+        self._output_dir = tempfile.mkdtemp()
+        for test_file in glob.glob(os.path.join(SCRIPT_DIR, 'testdata', '*')):
+            shutil.copy(test_file, self._output_dir)
+        self._libyuv_depsfile = os.path.join(self._output_dir, 'DEPS')
+        self._old_cr_depsfile = os.path.join(
+            self._output_dir, 'DEPS.chromium.old'
+        )
+        self._new_cr_depsfile = os.path.join(
+            self._output_dir, 'DEPS.chromium.new'
+        )
 
-  def tearDown(self):
-    shutil.rmtree(self._output_dir, ignore_errors=True)
-    self.assertEqual(self.fake.expectations, [])
-    setattr(roll_deps, '_RunCommand', self.old_RunCommand)
+        self.fake = FakeCmd()
+        self.old_RunCommand = getattr(roll_deps, '_RunCommand')
+        setattr(roll_deps, '_RunCommand', self.fake)
 
-  def testVarLookup(self):
-    local_scope = {'foo': 'wrong', 'vars': {'foo': 'bar'}}
-    lookup = roll_deps.VarLookup(local_scope)
-    self.assertEqual(lookup('foo'), 'bar')
+    def tearDown(self):
+        shutil.rmtree(self._output_dir, ignore_errors=True)
+        self.assertEqual(self.fake.expectations, [])
+        setattr(roll_deps, '_RunCommand', self.old_RunCommand)
 
-  def testUpdateDepsFile(self):
-    new_rev = 'aaaaabbbbbcccccdddddeeeeefffff0000011111'
+    def testVarLookup(self):
+        local_scope = {'foo': 'wrong', 'vars': {'foo': 'bar'}}
+        lookup = roll_deps.VarLookup(local_scope)
+        self.assertEqual(lookup('foo'), 'bar')
 
-    current_rev = TEST_DATA_VARS['chromium_revision']
-    UpdateDepsFile(self._libyuv_depsfile, current_rev, new_rev, [])
-    with open(self._libyuv_depsfile, 'r') as deps_file:
-      deps_contents = deps_file.read()
-      self.assertTrue(new_rev in deps_contents,
-                      'Failed to find %s in\n%s' % (new_rev, deps_contents))
+    def testUpdateDepsFile(self):
+        new_rev = 'aaaaabbbbbcccccdddddeeeeefffff0000011111'
 
-  def testParseDepsDict(self):
-    with open(self._libyuv_depsfile, 'r') as deps_file:
-      deps_contents = deps_file.read()
-    local_scope = ParseDepsDict(deps_contents)
-    vars_dict = local_scope['vars']
+        current_rev = TEST_DATA_VARS['chromium_revision']
+        UpdateDepsFile(self._libyuv_depsfile, current_rev, new_rev, [])
+        with open(self._libyuv_depsfile, 'r') as deps_file:
+            deps_contents = deps_file.read()
+            self.assertTrue(
+                new_rev in deps_contents,
+                'Failed to find %s in\n%s' % (new_rev, deps_contents),
+            )
 
-    def assertVar(variable_name):
-      self.assertEqual(vars_dict[variable_name], TEST_DATA_VARS[variable_name])
-    assertVar('chromium_git')
-    assertVar('chromium_revision')
-    self.assertEqual(len(local_scope['deps']), 3)
+    def testParseDepsDict(self):
+        with open(self._libyuv_depsfile, 'r') as deps_file:
+            deps_contents = deps_file.read()
+        local_scope = ParseDepsDict(deps_contents)
+        vars_dict = local_scope['vars']
 
-  def testGetMatchingDepsEntriesReturnsPathInSimpleCase(self):
-    entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/testing/gtest')
-    self.assertEqual(len(entries), 1)
-    self.assertEqual(entries[0], DEPS_ENTRIES['src/testing/gtest'])
+        def assertVar(variable_name):
+            self.assertEqual(
+                vars_dict[variable_name], TEST_DATA_VARS[variable_name]
+            )
 
-  def testGetMatchingDepsEntriesHandlesSimilarStartingPaths(self):
-    entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/testing')
-    self.assertEqual(len(entries), 2)
+        assertVar('chromium_git')
+        assertVar('chromium_revision')
+        self.assertEqual(len(local_scope['deps']), 3)
 
-  def testGetMatchingDepsEntriesHandlesTwoPathsWithIdenticalFirstParts(self):
-    entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/build')
-    self.assertEqual(len(entries), 1)
-    self.assertEqual(entries[0], DEPS_ENTRIES['src/build'])
+    def testGetMatchingDepsEntriesReturnsPathInSimpleCase(self):
+        entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/testing/gtest')
+        self.assertEqual(len(entries), 1)
+        self.assertEqual(entries[0], DEPS_ENTRIES['src/testing/gtest'])
 
-  def testCalculateChangedDeps(self):
-    _SetupGitLsRemoteCall(self.fake,
-        'https://chromium.googlesource.com/chromium/src/build', BUILD_NEW_REV)
-    libyuv_deps = ParseLocalDepsFile(self._libyuv_depsfile)
-    new_cr_deps = ParseLocalDepsFile(self._new_cr_depsfile)
-    changed_deps = CalculateChangedDeps(libyuv_deps, new_cr_deps)
-    self.assertEqual(len(changed_deps), 2)
-    self.assertEqual(changed_deps[0].path, 'src/build')
-    self.assertEqual(changed_deps[0].current_rev, BUILD_OLD_REV)
-    self.assertEqual(changed_deps[0].new_rev, BUILD_NEW_REV)
+    def testGetMatchingDepsEntriesHandlesSimilarStartingPaths(self):
+        entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/testing')
+        self.assertEqual(len(entries), 2)
 
-    self.assertEqual(changed_deps[1].path, 'src/buildtools')
-    self.assertEqual(changed_deps[1].current_rev, BUILDTOOLS_OLD_REV)
-    self.assertEqual(changed_deps[1].new_rev, BUILDTOOLS_NEW_REV)
+    def testGetMatchingDepsEntriesHandlesTwoPathsWithIdenticalFirstParts(self):
+        entries = GetMatchingDepsEntries(DEPS_ENTRIES, 'src/build')
+        self.assertEqual(len(entries), 1)
+        self.assertEqual(entries[0], DEPS_ENTRIES['src/build'])
+
+    def testCalculateChangedDeps(self):
+        _SetupGitLsRemoteCall(
+            self.fake,
+            'https://chromium.googlesource.com/chromium/src/build',
+            BUILD_NEW_REV,
+        )
+        libyuv_deps = ParseLocalDepsFile(self._libyuv_depsfile)
+        new_cr_deps = ParseLocalDepsFile(self._new_cr_depsfile)
+        changed_deps = CalculateChangedDeps(libyuv_deps, new_cr_deps)
+        self.assertEqual(len(changed_deps), 2)
+        self.assertEqual(changed_deps[0].path, 'src/build')
+        self.assertEqual(changed_deps[0].current_rev, BUILD_OLD_REV)
+        self.assertEqual(changed_deps[0].new_rev, BUILD_NEW_REV)
+
+        self.assertEqual(changed_deps[1].path, 'src/buildtools')
+        self.assertEqual(changed_deps[1].current_rev, BUILDTOOLS_OLD_REV)
+        self.assertEqual(changed_deps[1].new_rev, BUILDTOOLS_NEW_REV)
 
 
 def _SetupGitLsRemoteCall(cmd_fake, url, revision):
-  cmd = ['git', 'ls-remote', url, revision]
-  cmd_fake.add_expectation(cmd, _returns=(revision, None))
+    cmd = ['git', 'ls-remote', url, revision]
+    cmd_fake.add_expectation(cmd, _returns=(revision, None))
 
 
 if __name__ == '__main__':
-  unittest.main()
+    unittest.main()
diff --git a/tools_libyuv/get_landmines.py b/tools_libyuv/get_landmines.py
index 8b33483..ee0dbec 100755
--- a/tools_libyuv/get_landmines.py
+++ b/tools_libyuv/get_landmines.py
@@ -9,31 +9,30 @@
 # be found in the AUTHORS file in the root of the source tree.
 
 """
-This file emits the list of reasons why a particular build needs to be clobbered
-(or a list of 'landmines').
+This file emits the list of reasons why a particular build needs to be
+clobbered (or a list of 'landmines').
 """
 
 import sys
 
 
 def print_landmines():
-  """
-  ALL LANDMINES ARE EMITTED FROM HERE.
-  """
-  # DO NOT add landmines as part of a regular CL. Landmines are a last-effort
-  # bandaid fix if a CL that got landed has a build dependency bug and all bots
-  # need to be cleaned up. If you're writing a new CL that causes build
-  # dependency problems, fix the dependency problems instead of adding a
-  # landmine.
-  # See the Chromium version in src/build/get_landmines.py for usage examples.
-  print('Clobber to remove GYP artifacts after switching bots to GN.')
-  print('Another try to remove GYP artifacts after switching bots to GN.')
+    """ALL LANDMINES ARE EMITTED FROM HERE."""
+    # DO NOT add landmines as part of a regular CL. Landmines are a last-effort
+    # bandaid fix if a CL that got landed has a build dependency bug and all
+    # bots need to be cleaned up. If you're writing a new CL that causes build
+    # dependency problems, fix the dependency problems instead of adding a
+    # landmine.
+    # See the Chromium version in src/build/get_landmines.py for usage
+    # examples.
+    print('Clobber to remove GYP artifacts after switching bots to GN.')
+    print('Another try to remove GYP artifacts after switching bots to GN.')
 
 
 def main():
-  print_landmines()
-  return 0
+    print_landmines()
+    return 0
 
 
 if __name__ == '__main__':
-  sys.exit(main())
+    sys.exit(main())
diff --git a/unit_test/convert_argb_test.cc b/unit_test/convert_argb_test.cc
index aeee8a7..718afec 100644
--- a/unit_test/convert_argb_test.cc
+++ b/unit_test/convert_argb_test.cc
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include <time.h>
 
+#include "../unit_test/unit_test.h"
 #include "libyuv/basic_types.h"
 #include "libyuv/compare.h"
 #include "libyuv/convert.h"
@@ -19,10 +20,6 @@
 #include "libyuv/convert_from.h"
 #include "libyuv/convert_from_argb.h"
 #include "libyuv/cpu_id.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
-#include "../unit_test/unit_test.h"
 #include "libyuv/planar_functions.h"
 #include "libyuv/rotate.h"
 #include "libyuv/video_common.h"
@@ -2682,19 +2679,47 @@
   free_aligned_buffer_page_end(dest_rgb24);
 }
 
-TEST_F(LibYUVConvertTest, Test565) {
+TEST_F(LibYUVConvertTest, TestARGBToRGB565) {
   SIMD_ALIGNED(uint8_t orig_pixels[256][4]);
-  SIMD_ALIGNED(uint8_t pixels565[256][2]);
+  SIMD_ALIGNED(uint8_t dest_rgb565[256][2]);
 
   for (int i = 0; i < 256; ++i) {
     for (int j = 0; j < 4; ++j) {
       orig_pixels[i][j] = i;
     }
   }
-  ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1);
-  uint32_t checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381);
+  ARGBToRGB565(&orig_pixels[0][0], 0, &dest_rgb565[0][0], 0, 256, 1);
+  uint32_t checksum = HashDjb2(&dest_rgb565[0][0], sizeof(dest_rgb565), 5381);
   EXPECT_EQ(610919429u, checksum);
 }
+
+TEST_F(LibYUVConvertTest, TestYUY2ToARGB) {
+  SIMD_ALIGNED(uint8_t orig_pixels[256][2]);
+  SIMD_ALIGNED(uint8_t dest_argb[256][4]);
+
+  for (int i = 0; i < 256; ++i) {
+    for (int j = 0; j < 2; ++j) {
+      orig_pixels[i][j] = i;
+    }
+  }
+  YUY2ToARGB(&orig_pixels[0][0], 0, &dest_argb[0][0], 0, 256, 1);
+  uint32_t checksum = HashDjb2(&dest_argb[0][0], sizeof(dest_argb), 5381);
+  EXPECT_EQ(3486643515u, checksum);
+}
+
+TEST_F(LibYUVConvertTest, TestUYVYToARGB) {
+  SIMD_ALIGNED(uint8_t orig_pixels[256][2]);
+  SIMD_ALIGNED(uint8_t dest_argb[256][4]);
+
+  for (int i = 0; i < 256; ++i) {
+    for (int j = 0; j < 2; ++j) {
+      orig_pixels[i][j] = i;
+    }
+  }
+  UYVYToARGB(&orig_pixels[0][0], 0, &dest_argb[0][0], 0, 256, 1);
+  uint32_t checksum = HashDjb2(&dest_argb[0][0], sizeof(dest_argb), 5381);
+  EXPECT_EQ(3486643515u, checksum);
+}
 #endif  // !defined(LEAN_TESTS)
 
 }  // namespace libyuv
diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc
index f55bace..82163cb 100644
--- a/unit_test/convert_test.cc
+++ b/unit_test/convert_test.cc
@@ -188,6 +188,7 @@
 TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H420, uint8_t, 1, 2, 2, 10)
 TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2, 8)
 TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H012, uint16_t, 2, 2, 2, 8)
+TESTPLANARTOP(J420, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2, 8)
 TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I410, uint16_t, 2, 1, 1, 10)
 TESTPLANARTOP(I210, uint16_t, 2, 2, 1, I410, uint16_t, 2, 1, 1, 10)
 TESTPLANARTOP(I012, uint16_t, 2, 2, 2, I412, uint16_t, 2, 1, 1, 12)
@@ -326,18 +327,18 @@
 #undef TESTAPLANARTOPI
 
 // wrapper to keep API the same
-int I400ToNV21(const uint8_t* src_y,
-               int src_stride_y,
-               const uint8_t* /* src_u */,
-               int /* src_stride_u */,
-               const uint8_t* /* src_v */,
-               int /* src_stride_v */,
-               uint8_t* dst_y,
-               int dst_stride_y,
-               uint8_t* dst_vu,
-               int dst_stride_vu,
-               int width,
-               int height) {
+static int I400ToNV21(const uint8_t* src_y,
+                      int src_stride_y,
+                      const uint8_t* /* src_u */,
+                      int /* src_stride_u */,
+                      const uint8_t* /* src_v */,
+                      int /* src_stride_v */,
+                      uint8_t* dst_y,
+                      int dst_stride_y,
+                      uint8_t* dst_vu,
+                      int dst_stride_vu,
+                      int width,
+                      int height) {
   return I400ToNV21(src_y, src_stride_y, dst_y, dst_stride_y, dst_vu,
                     dst_stride_vu, width, height);
 }
@@ -452,6 +453,7 @@
 TESTPLANARTOBP(I444, uint8_t, 1, 1, 1, NV12, uint8_t, 1, 2, 2, 8)
 TESTPLANARTOBP(I444, uint8_t, 1, 1, 1, NV21, uint8_t, 1, 2, 2, 8)
 TESTPLANARTOBP(I400, uint8_t, 1, 2, 2, NV21, uint8_t, 1, 2, 2, 8)
+TESTPLANARTOBP(I010, uint16_t, 2, 2, 2, NV12, uint8_t, 1, 2, 2, 8)
 TESTPLANARTOBP(I010, uint16_t, 2, 2, 2, P010, uint16_t, 2, 2, 2, 10)
 TESTPLANARTOBP(I210, uint16_t, 2, 2, 1, P210, uint16_t, 2, 2, 1, 10)
 TESTPLANARTOBP(I012, uint16_t, 2, 2, 2, P012, uint16_t, 2, 2, 2, 12)
@@ -592,6 +594,7 @@
 TESTBPTOBP(P216, uint16_t, 2, 2, 1, P416, uint16_t, 2, 1, 1, 12, 1, 1)
 TESTBPTOBP(MM21, uint8_t, 1, 2, 2, NV12, uint8_t, 1, 2, 2, 8, 16, 32)
 TESTBPTOBP(MT2T, uint8_t, 10 / 8, 2, 2, P010, uint16_t, 2, 2, 2, 10, 16, 32)
+TESTBPTOBP(P010, uint16_t, 2, 2, 2, NV12, uint8_t, 1, 2, 2, 8, 1, 1)
 
 #define TESTATOPLANARI(FMT_A, BPP_A, YALIGN, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, \
                        W1280, N, NEG, OFF)                                     \
@@ -663,6 +666,7 @@
 TESTATOPLANAR(ARGB, 4, 1, I444, 1, 1)
 TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2)
 TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1)
+TESTATOPLANAR(ARGB, 4, 1, J444, 1, 1)
 TESTATOPLANAR(ABGR, 4, 1, J420, 2, 2)
 TESTATOPLANAR(ABGR, 4, 1, J422, 2, 1)
 #ifdef LITTLE_ENDIAN_ONLY_TEST
@@ -674,7 +678,9 @@
 TESTATOPLANAR(I400, 1, 1, I420, 2, 2)
 TESTATOPLANAR(J400, 1, 1, J420, 2, 2)
 TESTATOPLANAR(RAW, 3, 1, I420, 2, 2)
+TESTATOPLANAR(RAW, 3, 1, I444, 1, 1)
 TESTATOPLANAR(RAW, 3, 1, J420, 2, 2)
+TESTATOPLANAR(RAW, 3, 1, J444, 1, 1)
 TESTATOPLANAR(RGB24, 3, 1, I420, 2, 2)
 TESTATOPLANAR(RGB24, 3, 1, J420, 2, 2)
 TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2)
@@ -2070,7 +2076,7 @@
   }
 
   uint32_t checksum = HashDjb2(dest_j420, kSize * 3 / 2 * 2, 5381);
-  EXPECT_EQ(2755440272u, checksum);
+  EXPECT_EQ(223551344u, checksum);
 
   free_aligned_buffer_page_end(orig_rgb24);
   free_aligned_buffer_page_end(dest_j420);
@@ -2098,13 +2104,35 @@
   }
 
   uint32_t checksum = HashDjb2(dest_i420, kSize * 3 / 2 * 2, 5381);
-  EXPECT_EQ(1526656597u, checksum);
+  EXPECT_EQ(4197774805u, checksum);
 
   free_aligned_buffer_page_end(orig_rgb24);
   free_aligned_buffer_page_end(dest_i420);
 }
 #endif
 
+TEST_F(LibYUVConvertTest, TestJ420ToI420) {
+  const uint8_t src_y[12] = {0, 0, 128, 128, 255, 255,
+                             0, 0, 128, 128, 255, 255};
+  const uint8_t src_u[3] = {0, 128, 255};
+  const uint8_t src_v[3] = {0, 128, 255};
+  uint8_t dst_y[12];
+  uint8_t dst_u[3];
+  uint8_t dst_v[3];
+  ASSERT_EQ(J420ToI420(src_y, 6, src_u, 3, src_v, 3, dst_y, 6, dst_u, 3, dst_v,
+                       3, 6, 2),
+            0);
+  EXPECT_EQ(dst_y[0], 16);
+  EXPECT_EQ(dst_y[2], 126);
+  EXPECT_EQ(dst_y[4], 235);
+  EXPECT_EQ(dst_u[0], 16);
+  EXPECT_EQ(dst_u[1], 128);
+  EXPECT_EQ(dst_u[2], 240);
+  EXPECT_EQ(dst_v[0], 16);
+  EXPECT_EQ(dst_v[1], 128);
+  EXPECT_EQ(dst_v[2], 240);
+}
+
 #endif  // !defined(LEAN_TESTS)
 
 }  // namespace libyuv
diff --git a/unit_test/cpu_test.cc b/unit_test/cpu_test.cc
index 437b663..ebae292 100644
--- a/unit_test/cpu_test.cc
+++ b/unit_test/cpu_test.cc
@@ -8,9 +8,15 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef __linux__
+#include <ctype.h>
+#include <sys/utsname.h>
+#endif
+
 #include "../unit_test/unit_test.h"
 #include "libyuv/basic_types.h"
 #include "libyuv/cpu_id.h"
@@ -18,78 +24,201 @@
 
 namespace libyuv {
 
+#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
+    defined(_M_X64)
+TEST_F(LibYUVBaseTest, TestCpuId) {
+  int has_x86 = TestCpuFlag(kCpuHasX86);
+  if (has_x86) {
+    int cpu_info[4];
+    // Vendor ID:
+    // AuthenticAMD AMD processor
+    // CentaurHauls Centaur processor
+    // CyrixInstead Cyrix processor
+    // GenuineIntel Intel processor
+    // GenuineTMx86 Transmeta processor
+    // Geode by NSC National Semiconductor processor
+    // NexGenDriven NexGen processor
+    // RiseRiseRise Rise Technology processor
+    // SiS SiS SiS  SiS processor
+    // UMC UMC UMC  UMC processor
+    CpuId(0, 0, cpu_info);
+    cpu_info[0] = cpu_info[1];  // Reorder output
+    cpu_info[1] = cpu_info[3];
+    cpu_info[3] = 0;
+    printf("Cpu Vendor: %s 0x%x 0x%x 0x%x\n",
+           reinterpret_cast<char*>(&cpu_info[0]), cpu_info[0], cpu_info[1],
+           cpu_info[2]);
+    EXPECT_EQ(12u, strlen(reinterpret_cast<char*>(&cpu_info[0])));
+
+    // CPU Family and Model
+    // 3:0 - Stepping
+    // 7:4 - Model
+    // 11:8 - Family
+    // 13:12 - Processor Type
+    // 19:16 - Extended Model
+    // 27:20 - Extended Family
+    CpuId(1, 0, cpu_info);
+    int family = ((cpu_info[0] >> 8) & 0x0f) | ((cpu_info[0] >> 16) & 0xff0);
+    int model = ((cpu_info[0] >> 4) & 0x0f) | ((cpu_info[0] >> 12) & 0xf0);
+    printf("Cpu Family %d (0x%x), Model %d (0x%x)\n", family, family, model,
+           model);
+  }
+}
+#endif
+
+#ifdef __linux__
+static void KernelVersion(int* version) {
+  struct utsname buffer;
+  int i = 0;
+
+  version[0] = version[1] = 0;
+  if (uname(&buffer) == 0) {
+    char* v = buffer.release;
+    for (i = 0; *v && i < 2; ++v) {
+      if (isdigit(*v)) {
+        version[i++] = (int)strtol(v, &v, 10);
+      }
+    }
+  }
+}
+#endif
+
 TEST_F(LibYUVBaseTest, TestCpuHas) {
-  int cpu_flags = TestCpuFlag(-1);
-  printf("Cpu Flags 0x%x\n", cpu_flags);
+#if defined(__linux__)
+  {
+    int kernelversion[2];
+    KernelVersion(kernelversion);
+    printf("Kernel Version %d.%d\n", kernelversion[0], kernelversion[1]);
+  }
+#endif  // defined(__linux__)
+
 #if defined(__arm__) || defined(__aarch64__)
   int has_arm = TestCpuFlag(kCpuHasARM);
-  printf("Has ARM 0x%x\n", has_arm);
-  int has_neon = TestCpuFlag(kCpuHasNEON);
-  printf("Has NEON 0x%x\n", has_neon);
-#endif
-#if defined(__riscv) && defined(__linux__)
+  if (has_arm) {
+    int has_neon = TestCpuFlag(kCpuHasNEON);
+    int has_neon_dotprod = TestCpuFlag(kCpuHasNeonDotProd);
+    int has_neon_i8mm = TestCpuFlag(kCpuHasNeonI8MM);
+    int has_sve = TestCpuFlag(kCpuHasSVE);
+    int has_sve2 = TestCpuFlag(kCpuHasSVE2);
+    int has_sme = TestCpuFlag(kCpuHasSME);
+    printf("Has Arm 0x%x\n", has_arm);
+    printf("Has Neon 0x%x\n", has_neon);
+    printf("Has Neon DotProd 0x%x\n", has_neon_dotprod);
+    printf("Has Neon I8MM 0x%x\n", has_neon_i8mm);
+    printf("Has SVE 0x%x\n", has_sve);
+    printf("Has SVE2 0x%x\n", has_sve2);
+    printf("Has SME 0x%x\n", has_sme);
+
+#if defined(__aarch64__)
+    // Read and print the SVE and SME vector lengths.
+    if (has_sve) {
+      int sve_vl;
+      asm(".inst 0x04bf5020    \n"  // rdvl x0, #1
+          "mov %w[sve_vl], w0  \n"
+          : [sve_vl] "=r"(sve_vl)  // %[sve_vl]
+          :
+          : "x0");
+      printf("SVE vector length: %d bytes\n", sve_vl);
+    }
+    if (has_sme) {
+      int sme_vl;
+      asm(".inst 0x04bf5820    \n"  // rdsvl x0, #1
+          "mov %w[sme_vl], w0  \n"
+          : [sme_vl] "=r"(sme_vl)  // %[sme_vl]
+          :
+          : "x0");
+      printf("SME vector length: %d bytes\n", sme_vl);
+    }
+#endif  // defined(__aarch64__)
+  }
+#endif  // if defined(__arm__) || defined(__aarch64__)
+
+#if defined(__riscv)
   int has_riscv = TestCpuFlag(kCpuHasRISCV);
-  printf("Has RISCV 0x%x\n", has_riscv);
-  int has_rvv = TestCpuFlag(kCpuHasRVV);
-  printf("Has RVV 0x%x\n", has_rvv);
-  int has_rvvzvfh = TestCpuFlag(kCpuHasRVVZVFH);
-  printf("Has RVVZVFH 0x%x\n", has_rvvzvfh);
-#endif
+  if (has_riscv) {
+    int has_rvv = TestCpuFlag(kCpuHasRVV);
+    printf("Has RISCV 0x%x\n", has_riscv);
+    printf("Has RVV 0x%x\n", has_rvv);
+
+    // Read and print the RVV vector length.
+    if (has_rvv) {
+      register uint32_t vlenb __asm__("t0");
+      __asm__(".word 0xC22022F3" /* CSRR t0, vlenb */ : "=r"(vlenb));
+      printf("RVV vector length: %d bytes\n", vlenb);
+    }
+  }
+#endif  // defined(__riscv)
+
+#if defined(__mips__)
+  int has_mips = TestCpuFlag(kCpuHasMIPS);
+  if (has_mips) {
+    int has_msa = TestCpuFlag(kCpuHasMSA);
+    printf("Has MIPS 0x%x\n", has_mips);
+    printf("Has MSA 0x%x\n", has_msa);
+  }
+#endif  // defined(__mips__)
+
+#if defined(__loongarch__)
+  int has_loongarch = TestCpuFlag(kCpuHasLOONGARCH);
+  if (has_loongarch) {
+    int has_lsx = TestCpuFlag(kCpuHasLSX);
+    int has_lasx = TestCpuFlag(kCpuHasLASX);
+    printf("Has LOONGARCH 0x%x\n", has_loongarch);
+    printf("Has LSX 0x%x\n", has_lsx);
+    printf("Has LASX 0x%x\n", has_lasx);
+  }
+#endif  // defined(__loongarch__)
+
 #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
     defined(_M_X64)
   int has_x86 = TestCpuFlag(kCpuHasX86);
-  int has_sse2 = TestCpuFlag(kCpuHasSSE2);
-  int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
-  int has_sse41 = TestCpuFlag(kCpuHasSSE41);
-  int has_sse42 = TestCpuFlag(kCpuHasSSE42);
-  int has_avx = TestCpuFlag(kCpuHasAVX);
-  int has_avx2 = TestCpuFlag(kCpuHasAVX2);
-  int has_erms = TestCpuFlag(kCpuHasERMS);
-  int has_fma3 = TestCpuFlag(kCpuHasFMA3);
-  int has_f16c = TestCpuFlag(kCpuHasF16C);
-  int has_avx512bw = TestCpuFlag(kCpuHasAVX512BW);
-  int has_avx512vl = TestCpuFlag(kCpuHasAVX512VL);
-  int has_avx512vnni = TestCpuFlag(kCpuHasAVX512VNNI);
-  int has_avx512vbmi = TestCpuFlag(kCpuHasAVX512VBMI);
-  int has_avx512vbmi2 = TestCpuFlag(kCpuHasAVX512VBMI2);
-  int has_avx512vbitalg = TestCpuFlag(kCpuHasAVX512VBITALG);
-  int has_avx10 = TestCpuFlag(kCpuHasAVX10);
-  int has_avxvnni = TestCpuFlag(kCpuHasAVXVNNI);
-  int has_avxvnniint8 = TestCpuFlag(kCpuHasAVXVNNIINT8);
-  printf("Has X86 0x%x\n", has_x86);
-  printf("Has SSE2 0x%x\n", has_sse2);
-  printf("Has SSSE3 0x%x\n", has_ssse3);
-  printf("Has SSE41 0x%x\n", has_sse41);
-  printf("Has SSE42 0x%x\n", has_sse42);
-  printf("Has AVX 0x%x\n", has_avx);
-  printf("Has AVX2 0x%x\n", has_avx2);
-  printf("Has ERMS 0x%x\n", has_erms);
-  printf("Has FMA3 0x%x\n", has_fma3);
-  printf("Has F16C 0x%x\n", has_f16c);
-  printf("Has AVX512BW 0x%x\n", has_avx512bw);
-  printf("Has AVX512VL 0x%x\n", has_avx512vl);
-  printf("Has AVX512VNNI 0x%x\n", has_avx512vnni);
-  printf("Has AVX512VBMI 0x%x\n", has_avx512vbmi);
-  printf("Has AVX512VBMI2 0x%x\n", has_avx512vbmi2);
-  printf("Has AVX512VBITALG 0x%x\n", has_avx512vbitalg);
-  printf("Has AVX10 0x%x\n", has_avx10);
-  printf("HAS AVXVNNI 0x%x\n", has_avxvnni);
-  printf("Has AVXVNNIINT8 0x%x\n", has_avxvnniint8);
-#endif
-#if defined(__mips__)
-  int has_mips = TestCpuFlag(kCpuHasMIPS);
-  printf("Has MIPS 0x%x\n", has_mips);
-  int has_msa = TestCpuFlag(kCpuHasMSA);
-  printf("Has MSA 0x%x\n", has_msa);
-#endif
-#if defined(__loongarch__)
-  int has_loongarch = TestCpuFlag(kCpuHasLOONGARCH);
-  printf("Has LOONGARCH 0x%x\n", has_loongarch);
-  int has_lsx = TestCpuFlag(kCpuHasLSX);
-  printf("Has LSX 0x%x\n", has_lsx);
-  int has_lasx = TestCpuFlag(kCpuHasLASX);
-  printf("Has LASX 0x%x\n", has_lasx);
-#endif
+  if (has_x86) {
+    int has_sse2 = TestCpuFlag(kCpuHasSSE2);
+    int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
+    int has_sse41 = TestCpuFlag(kCpuHasSSE41);
+    int has_sse42 = TestCpuFlag(kCpuHasSSE42);
+    int has_avx = TestCpuFlag(kCpuHasAVX);
+    int has_avx2 = TestCpuFlag(kCpuHasAVX2);
+    int has_erms = TestCpuFlag(kCpuHasERMS);
+    int has_fsmr = TestCpuFlag(kCpuHasFSMR);
+    int has_fma3 = TestCpuFlag(kCpuHasFMA3);
+    int has_f16c = TestCpuFlag(kCpuHasF16C);
+    int has_avx512bw = TestCpuFlag(kCpuHasAVX512BW);
+    int has_avx512vl = TestCpuFlag(kCpuHasAVX512VL);
+    int has_avx512vnni = TestCpuFlag(kCpuHasAVX512VNNI);
+    int has_avx512vbmi = TestCpuFlag(kCpuHasAVX512VBMI);
+    int has_avx512vbmi2 = TestCpuFlag(kCpuHasAVX512VBMI2);
+    int has_avx512vbitalg = TestCpuFlag(kCpuHasAVX512VBITALG);
+    int has_avx10 = TestCpuFlag(kCpuHasAVX10);
+    int has_avx10_2 = TestCpuFlag(kCpuHasAVX10_2);
+    int has_avxvnni = TestCpuFlag(kCpuHasAVXVNNI);
+    int has_avxvnniint8 = TestCpuFlag(kCpuHasAVXVNNIINT8);
+    int has_amxint8 = TestCpuFlag(kCpuHasAMXINT8);
+    printf("Has X86 0x%x\n", has_x86);
+    printf("Has SSE2 0x%x\n", has_sse2);
+    printf("Has SSSE3 0x%x\n", has_ssse3);
+    printf("Has SSE4.1 0x%x\n", has_sse41);
+    printf("Has SSE4.2 0x%x\n", has_sse42);
+    printf("Has AVX 0x%x\n", has_avx);
+    printf("Has AVX2 0x%x\n", has_avx2);
+    printf("Has ERMS 0x%x\n", has_erms);
+    printf("Has FSMR 0x%x\n", has_fsmr);
+    printf("Has FMA3 0x%x\n", has_fma3);
+    printf("Has F16C 0x%x\n", has_f16c);
+    printf("Has AVX512BW 0x%x\n", has_avx512bw);
+    printf("Has AVX512VL 0x%x\n", has_avx512vl);
+    printf("Has AVX512VNNI 0x%x\n", has_avx512vnni);
+    printf("Has AVX512VBMI 0x%x\n", has_avx512vbmi);
+    printf("Has AVX512VBMI2 0x%x\n", has_avx512vbmi2);
+    printf("Has AVX512VBITALG 0x%x\n", has_avx512vbitalg);
+    printf("Has AVX10 0x%x\n", has_avx10);
+    printf("Has AVX10_2 0x%x\n", has_avx10_2);
+    printf("HAS AVXVNNI 0x%x\n", has_avxvnni);
+    printf("Has AVXVNNIINT8 0x%x\n", has_avxvnniint8);
+    printf("Has AMXINT8 0x%x\n", has_amxint8);
+  }
+#endif  // defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) ||
+        // defined(_M_X64)
 }
 
 TEST_F(LibYUVBaseTest, TestCompilerMacros) {
@@ -142,6 +271,9 @@
 #ifdef __riscv_v_intrinsic
   printf("__riscv_v_intrinsic %d\n", __riscv_v_intrinsic);
 #endif
+#ifdef __riscv_zve64x
+  printf("__riscv_zve64x %d\n", __riscv_zve64x);
+#endif
 #ifdef __APPLE__
   printf("__APPLE__ %d\n", __APPLE__);
 #endif
@@ -199,48 +331,6 @@
 #endif
 }
 
-#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
-    defined(_M_X64)
-TEST_F(LibYUVBaseTest, TestCpuId) {
-  int has_x86 = TestCpuFlag(kCpuHasX86);
-  if (has_x86) {
-    int cpu_info[4];
-    // Vendor ID:
-    // AuthenticAMD AMD processor
-    // CentaurHauls Centaur processor
-    // CyrixInstead Cyrix processor
-    // GenuineIntel Intel processor
-    // GenuineTMx86 Transmeta processor
-    // Geode by NSC National Semiconductor processor
-    // NexGenDriven NexGen processor
-    // RiseRiseRise Rise Technology processor
-    // SiS SiS SiS  SiS processor
-    // UMC UMC UMC  UMC processor
-    CpuId(0, 0, cpu_info);
-    cpu_info[0] = cpu_info[1];  // Reorder output
-    cpu_info[1] = cpu_info[3];
-    cpu_info[3] = 0;
-    printf("Cpu Vendor: %s 0x%x 0x%x 0x%x\n",
-           reinterpret_cast<char*>(&cpu_info[0]), cpu_info[0], cpu_info[1],
-           cpu_info[2]);
-    EXPECT_EQ(12u, strlen(reinterpret_cast<char*>(&cpu_info[0])));
-
-    // CPU Family and Model
-    // 3:0 - Stepping
-    // 7:4 - Model
-    // 11:8 - Family
-    // 13:12 - Processor Type
-    // 19:16 - Extended Model
-    // 27:20 - Extended Family
-    CpuId(1, 0, cpu_info);
-    int family = ((cpu_info[0] >> 8) & 0x0f) | ((cpu_info[0] >> 16) & 0xff0);
-    int model = ((cpu_info[0] >> 4) & 0x0f) | ((cpu_info[0] >> 12) & 0xf0);
-    printf("Cpu Family %d (0x%x), Model %d (0x%x)\n", family, family, model,
-           model);
-  }
-}
-#endif
-
 static int FileExists(const char* file_name) {
   FILE* f = fopen(file_name, "r");
   if (!f) {
@@ -250,21 +340,20 @@
   return 1;
 }
 
-TEST_F(LibYUVBaseTest, TestLinuxNeon) {
+TEST_F(LibYUVBaseTest, TestLinuxArm) {
   if (FileExists("../../unit_test/testdata/arm_v7.txt")) {
     printf("Note: testing to load \"../../unit_test/testdata/arm_v7.txt\"\n");
 
     EXPECT_EQ(0, ArmCpuCaps("../../unit_test/testdata/arm_v7.txt"));
     EXPECT_EQ(kCpuHasNEON, ArmCpuCaps("../../unit_test/testdata/tegra3.txt"));
-    EXPECT_EQ(kCpuHasNEON, ArmCpuCaps("../../unit_test/testdata/juno.txt"));
   } else {
     printf("WARNING: unable to load \"../../unit_test/testdata/arm_v7.txt\"\n");
   }
-#if defined(__linux__) && defined(__ARM_NEON__)
+#if defined(__linux__) && defined(__ARM_NEON__) && !defined(__aarch64__)
   if (FileExists("/proc/cpuinfo")) {
     if (kCpuHasNEON != ArmCpuCaps("/proc/cpuinfo")) {
-      // This can happen on ARM emulator but /proc/cpuinfo is from host.
-      printf("WARNING: Neon build enabled but CPU does not have NEON\n");
+      // This can happen on Arm emulator but /proc/cpuinfo is from host.
+      printf("WARNING: Neon build enabled but CPU does not have Neon\n");
     }
   } else {
     printf("WARNING: unable to load \"/proc/cpuinfo\"\n");
@@ -272,6 +361,29 @@
 #endif
 }
 
+#if defined(__linux__) && defined(__aarch64__)
+TEST_F(LibYUVBaseTest, TestLinuxAArch64) {
+  // Values taken from a Cortex-A57 machine, only Neon available.
+  EXPECT_EQ(kCpuHasNEON, AArch64CpuCaps(0xffU, 0x0U));
+
+  // Values taken from a Google Pixel 7.
+  int expected = kCpuHasNEON | kCpuHasNeonDotProd;
+  EXPECT_EQ(expected, AArch64CpuCaps(0x119fffU, 0x0U));
+
+  // Values taken from a Google Pixel 8.
+  expected = kCpuHasNEON | kCpuHasNeonDotProd | kCpuHasNeonI8MM | kCpuHasSVE |
+             kCpuHasSVE2;
+  EXPECT_EQ(expected, AArch64CpuCaps(0x3fffffffU, 0x2f33fU));
+
+  // Values taken from a Neoverse N2 machine.
+  EXPECT_EQ(expected, AArch64CpuCaps(0x3fffffffU, 0x2f3ffU));
+
+  // Check for SME feature detection.
+  expected |= kCpuHasSME;
+  EXPECT_EQ(expected, AArch64CpuCaps(0x3fffffffU, 0x82f3ffU));
+}
+#endif
+
 TEST_F(LibYUVBaseTest, TestLinuxMipsMsa) {
   if (FileExists("../../unit_test/testdata/mips.txt")) {
     printf("Note: testing to load \"../../unit_test/testdata/mips.txt\"\n");
diff --git a/unit_test/cpu_thread_test.cc b/unit_test/cpu_thread_test.cc
index 69aab74..b6c0fa0 100644
--- a/unit_test/cpu_thread_test.cc
+++ b/unit_test/cpu_thread_test.cc
@@ -27,7 +27,7 @@
 namespace libyuv {
 
 #ifdef LIBYUV_HAVE_PTHREAD
-void* ThreadMain(void* arg) {
+static void* ThreadMain(void* arg) {
   int* flags = static_cast<int*>(arg);
 
   *flags = TestCpuFlag(kCpuInitialized);
diff --git a/unit_test/planar_test.cc b/unit_test/planar_test.cc
index ec1d72e..576696b 100644
--- a/unit_test/planar_test.cc
+++ b/unit_test/planar_test.cc
@@ -1551,98 +1551,78 @@
 #endif
 }
 
-TEST_F(LibYUVPlanarTest, TestCopyPlane) {
-  int err = 0;
-  int yw = benchmark_width_;
-  int yh = benchmark_height_;
-  int b = 12;
-  int i, j;
-
-  int y_plane_size = (yw + b * 2) * (yh + b * 2);
-  align_buffer_page_end(orig_y, y_plane_size);
+static int TestCopyPlane(int benchmark_width,
+                         int benchmark_height,
+                         int benchmark_iterations,
+                         int disable_cpu_flags,
+                         int benchmark_cpu_info,
+                         int invert,
+                         int off) {
+  const int y_plane_size = benchmark_width * benchmark_height;
+  align_buffer_page_end(orig_y, y_plane_size + off);
   align_buffer_page_end(dst_c, y_plane_size);
   align_buffer_page_end(dst_opt, y_plane_size);
 
-  memset(orig_y, 0, y_plane_size);
-  memset(dst_c, 0, y_plane_size);
-  memset(dst_opt, 0, y_plane_size);
-
-  // Fill image buffers with random data.
-  for (i = b; i < (yh + b); ++i) {
-    for (j = b; j < (yw + b); ++j) {
-      orig_y[i * (yw + b * 2) + j] = fastrand() & 0xff;
-    }
-  }
-
-  // Fill destination buffers with random data.
-  for (i = 0; i < y_plane_size; ++i) {
-    uint8_t random_number = fastrand() & 0x7f;
-    dst_c[i] = random_number;
-    dst_opt[i] = dst_c[i];
-  }
-
-  int y_off = b * (yw + b * 2) + b;
-
-  int y_st = yw + b * 2;
-  int stride = 8;
-
-  // Disable all optimizations.
-  MaskCpuFlags(disable_cpu_flags_);
-  for (j = 0; j < benchmark_iterations_; j++) {
-    CopyPlane(orig_y + y_off, y_st, dst_c + y_off, stride, yw, yh);
-  }
-
-  // Enable optimizations.
-  MaskCpuFlags(benchmark_cpu_info_);
-  for (j = 0; j < benchmark_iterations_; j++) {
-    CopyPlane(orig_y + y_off, y_st, dst_opt + y_off, stride, yw, yh);
-  }
-
-  for (i = 0; i < y_plane_size; ++i) {
-    if (dst_c[i] != dst_opt[i]) {
-      ++err;
-    }
-  }
-
-  free_aligned_buffer_page_end(orig_y);
-  free_aligned_buffer_page_end(dst_c);
-  free_aligned_buffer_page_end(dst_opt);
-
-  EXPECT_EQ(0, err);
-}
-
-TEST_F(LibYUVPlanarTest, CopyPlane_Opt) {
-  int i;
-  int y_plane_size = benchmark_width_ * benchmark_height_;
-  align_buffer_page_end(orig_y, y_plane_size);
-  align_buffer_page_end(dst_c, y_plane_size);
-  align_buffer_page_end(dst_opt, y_plane_size);
-
-  MemRandomize(orig_y, y_plane_size);
+  MemRandomize(orig_y + off, y_plane_size);
   memset(dst_c, 1, y_plane_size);
   memset(dst_opt, 2, y_plane_size);
 
   // Disable all optimizations.
-  MaskCpuFlags(disable_cpu_flags_);
-  for (i = 0; i < benchmark_iterations_; i++) {
-    CopyPlane(orig_y, benchmark_width_, dst_c, benchmark_width_,
-              benchmark_width_, benchmark_height_);
+  MaskCpuFlags(disable_cpu_flags);
+  for (int i = 0; i < benchmark_iterations; i++) {
+    CopyPlane(orig_y + off, benchmark_width, dst_c, benchmark_width,
+              benchmark_width, benchmark_height * invert);
   }
 
   // Enable optimizations.
-  MaskCpuFlags(benchmark_cpu_info_);
-  for (i = 0; i < benchmark_iterations_; i++) {
-    CopyPlane(orig_y, benchmark_width_, dst_opt, benchmark_width_,
-              benchmark_width_, benchmark_height_);
+  MaskCpuFlags(benchmark_cpu_info);
+  for (int i = 0; i < benchmark_iterations; i++) {
+    CopyPlane(orig_y + off, benchmark_width, dst_opt, benchmark_width,
+              benchmark_width, benchmark_height * invert);
   }
 
-  for (i = 0; i < y_plane_size; ++i) {
-    EXPECT_EQ(dst_c[i], dst_opt[i]);
+  int max_diff = 0;
+  for (int i = 0; i < y_plane_size; ++i) {
+    int abs_diff =
+        abs(static_cast<int>(dst_c[i]) - static_cast<int>(dst_opt[i]));
+    if (abs_diff > max_diff) {
+      max_diff = abs_diff;
+    }
   }
 
   free_aligned_buffer_page_end(orig_y);
   free_aligned_buffer_page_end(dst_c);
   free_aligned_buffer_page_end(dst_opt);
+
+  return max_diff;
+}
+
+TEST_F(LibYUVPlanarTest, CopyPlane_Any) {
+  int max_diff = TestCopyPlane(benchmark_width_ + 1, benchmark_height_,
+                               benchmark_iterations_, disable_cpu_flags_,
+                               benchmark_cpu_info_, +1, 0);
+  EXPECT_LE(max_diff, 0);
+}
+
+TEST_F(LibYUVPlanarTest, CopyPlane_Unaligned) {
+  int max_diff =
+      TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
+                    disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
+  EXPECT_LE(max_diff, 0);
+}
+
+TEST_F(LibYUVPlanarTest, CopyPlane_Invert) {
+  int max_diff =
+      TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
+                    disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
+  EXPECT_LE(max_diff, 0);
+}
+
+TEST_F(LibYUVPlanarTest, CopyPlane_Opt) {
+  int max_diff =
+      TestCopyPlane(benchmark_width_, benchmark_height_, benchmark_iterations_,
+                    disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
+  EXPECT_LE(max_diff, 0);
 }
 
 TEST_F(LibYUVPlanarTest, TestCopyPlaneZero) {
@@ -1906,28 +1886,28 @@
   int max_diff = TestMultiply(benchmark_width_ + 1, benchmark_height_,
                               benchmark_iterations_, disable_cpu_flags_,
                               benchmark_cpu_info_, +1, 0);
-  EXPECT_LE(max_diff, 1);
+  EXPECT_LE(max_diff, 0);
 }
 
 TEST_F(LibYUVPlanarTest, ARGBMultiply_Unaligned) {
   int max_diff =
       TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
                    disable_cpu_flags_, benchmark_cpu_info_, +1, 1);
-  EXPECT_LE(max_diff, 1);
+  EXPECT_LE(max_diff, 0);
 }
 
 TEST_F(LibYUVPlanarTest, ARGBMultiply_Invert) {
   int max_diff =
       TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
                    disable_cpu_flags_, benchmark_cpu_info_, -1, 0);
-  EXPECT_LE(max_diff, 1);
+  EXPECT_LE(max_diff, 0);
 }
 
 TEST_F(LibYUVPlanarTest, ARGBMultiply_Opt) {
   int max_diff =
       TestMultiply(benchmark_width_, benchmark_height_, benchmark_iterations_,
                    disable_cpu_flags_, benchmark_cpu_info_, +1, 0);
-  EXPECT_LE(max_diff, 1);
+  EXPECT_LE(max_diff, 0);
 }
 
 static int TestAdd(int width,
@@ -2496,42 +2476,45 @@
   }
 }
 
-int TestHalfFloatPlane(int benchmark_width,
-                       int benchmark_height,
-                       int benchmark_iterations,
-                       int disable_cpu_flags,
-                       int benchmark_cpu_info,
-                       float scale,
-                       int mask) {
+static int TestHalfFloatPlane(int benchmark_width,
+                              int benchmark_height,
+                              int benchmark_iterations,
+                              int disable_cpu_flags,
+                              int benchmark_cpu_info,
+                              float scale,
+                              int mask,
+                              int invert,
+                              int off) {
   int i, j;
   const int y_plane_size = benchmark_width * benchmark_height * 2;
+  align_buffer_page_end(orig_y, y_plane_size + off);
+  align_buffer_page_end(dst_c, y_plane_size);
+  align_buffer_page_end(dst_opt, y_plane_size);
 
-  align_buffer_page_end(orig_y, y_plane_size * 3);
-  uint8_t* dst_opt = orig_y + y_plane_size;
-  uint8_t* dst_c = orig_y + y_plane_size * 2;
-
-  MemRandomize(orig_y, y_plane_size);
-  memset(dst_c, 0, y_plane_size);
-  memset(dst_opt, 1, y_plane_size);
+  MemRandomize(orig_y + off, y_plane_size);
+  memset(dst_c, 1, y_plane_size);
+  memset(dst_opt, 2, y_plane_size);
 
   for (i = 0; i < y_plane_size / 2; ++i) {
-    reinterpret_cast<uint16_t*>(orig_y)[i] &= mask;
+    reinterpret_cast<uint16_t*>(orig_y + off)[i] &= mask;
   }
 
   // Disable all optimizations.
   MaskCpuFlags(disable_cpu_flags);
   for (j = 0; j < benchmark_iterations; j++) {
-    HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y), benchmark_width * 2,
-                   reinterpret_cast<uint16_t*>(dst_c), benchmark_width * 2,
-                   scale, benchmark_width, benchmark_height);
+    HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y + off),
+                   benchmark_width * 2, reinterpret_cast<uint16_t*>(dst_c),
+                   benchmark_width * 2, scale, benchmark_width,
+                   benchmark_height * invert);
   }
 
   // Enable optimizations.
   MaskCpuFlags(benchmark_cpu_info);
   for (j = 0; j < benchmark_iterations; j++) {
-    HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y), benchmark_width * 2,
-                   reinterpret_cast<uint16_t*>(dst_opt), benchmark_width * 2,
-                   scale, benchmark_width, benchmark_height);
+    HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y + off),
+                   benchmark_width * 2, reinterpret_cast<uint16_t*>(dst_opt),
+                   benchmark_width * 2, scale, benchmark_width,
+                   benchmark_height * invert);
   }
 
   int max_diff = 0;
@@ -2545,97 +2528,130 @@
   }
 
   free_aligned_buffer_page_end(orig_y);
+  free_aligned_buffer_page_end(dst_c);
+  free_aligned_buffer_page_end(dst_opt);
   return max_diff;
 }
 
-#if defined(__arm__)
-static void EnableFlushDenormalToZero(void) {
-  uint32_t cw;
-  __asm__ __volatile__(
-      "vmrs   %0, fpscr         \n"
-      "orr    %0, %0, #0x1000000        \n"
-      "vmsr   fpscr, %0         \n"
-      : "=r"(cw)::"memory");
-}
-#endif
-
-// 5 bit exponent with bias of 15 will underflow to a denormal if scale causes
-// exponent to be less than 0.  15 - log2(65536) = -1/  This shouldnt normally
-// happen since scale is 1/(1<<bits) where bits is 9, 10 or 12.
-
-TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_denormal) {
-// 32 bit arm rounding on denormal case is off by 1 compared to C.
-#if defined(__arm__)
-  EnableFlushDenormalToZero();
-#endif
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 65536.0f, 65535);
-  EXPECT_EQ(0, diff);
-}
-
 TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_One) {
   int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
                                 benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f, 65535);
+                                benchmark_cpu_info_, 1.0f, 65535, +1, 0);
   EXPECT_LE(diff, 1);
 }
 
 TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_Opt) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 4096.0f, 65535);
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
+  EXPECT_EQ(0, diff);
+}
+
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_12bit_Opt) {
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4095.0f, 4095, +1, 0);
   EXPECT_EQ(0, diff);
 }
 
 TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_10bit_Opt) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 1024.0f, 1023);
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 1023.0f, 1023, +1, 0);
   EXPECT_EQ(0, diff);
 }
 
 TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_9bit_Opt) {
   int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
                                 benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 512.0f, 511);
+                                benchmark_cpu_info_, 1.0f / 511.0f, 511, +1, 0);
+  EXPECT_EQ(0, diff);
+}
+
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Any) {
+  int diff = TestHalfFloatPlane(
+      benchmark_width_ + 1, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 0);
+  EXPECT_EQ(0, diff);
+}
+
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Unaligned) {
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 2);
+  EXPECT_EQ(0, diff);
+}
+
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Invert) {
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, -1, 0);
   EXPECT_EQ(0, diff);
 }
 
 TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Opt) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 4096.0f, 4095);
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 4096.0f, 4095, +1, 0);
   EXPECT_EQ(0, diff);
 }
 
-TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_Offby1) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f / 4095.0f, 4095);
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_denormal) {
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
   EXPECT_EQ(0, diff);
 }
 
-TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_One) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f, 2047);
+#if defined(__arm__)
+static void EnableFlushDenormalToZero(void) {
+  uint32_t cw;
+  asm volatile(
+      "vmrs   %0, fpscr                 \n"
+      "orr    %0, %0, #0x1000000        \n"
+      "vmsr   fpscr, %0                 \n"
+      : "=r"(cw)::"memory", "cc");  // Clobber List
+}
+
+static void DisableFlushDenormalToZero(void) {
+  uint32_t cw;
+  asm volatile(
+      "vmrs   %0, fpscr                 \n"
+      "bic    %0, %0, #0x1000000        \n"
+      "vmsr   fpscr, %0                 \n"
+      : "=r"(cw)::"memory", "cc");  // Clobber List
+}
+
+// 5 bit exponent with bias of 15 will underflow to a denormal if scale causes
+// exponent to be less than 0.  15 - log2(65536) = -1/  This shouldnt normally
+// happen since scale is 1/(1<<bits) where bits is 9, 10 or 12.
+
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_16bit_flush_denormal) {
+  // 32 bit arm rounding on denormal case is off by 1 compared to C.
+  EnableFlushDenormalToZero();
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 65535.0f, 65535, +1, 0);
+  DisableFlushDenormalToZero();
   EXPECT_EQ(0, diff);
 }
 
-TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_12bit_One) {
-  int diff = TestHalfFloatPlane(benchmark_width_, benchmark_height_,
-                                benchmark_iterations_, disable_cpu_flags_,
-                                benchmark_cpu_info_, 1.0f, 4095);
-  EXPECT_LE(diff, 1);
+TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_10bit_flush_denormal) {
+  EnableFlushDenormalToZero();
+  int diff = TestHalfFloatPlane(
+      benchmark_width_, benchmark_height_, benchmark_iterations_,
+      disable_cpu_flags_, benchmark_cpu_info_, 1.0f / 1023.0f, 1023, +1, 0);
+  DisableFlushDenormalToZero();
+  EXPECT_EQ(0, diff);
 }
+#endif  // defined(__arm__)
 
-float TestByteToFloat(int benchmark_width,
-                      int benchmark_height,
-                      int benchmark_iterations,
-                      int disable_cpu_flags,
-                      int benchmark_cpu_info,
-                      float scale) {
+static float TestByteToFloat(int benchmark_width,
+                             int benchmark_height,
+                             int benchmark_iterations,
+                             int disable_cpu_flags,
+                             int benchmark_cpu_info,
+                             float scale) {
   int i, j;
   const int y_plane_size = benchmark_width * benchmark_height;
 
@@ -3146,35 +3162,44 @@
   // Round count up to multiple of 16
   const int kPixels = benchmark_width_ * benchmark_height_;
   align_buffer_page_end(src_pixels, kPixels * 3);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(dst_pixels_opt, kPixels * 3);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
   align_buffer_page_end(dst_pixels_c, kPixels * 3);
+  align_buffer_page_end(dst_pixels_opt, kPixels * 3);
 
   MemRandomize(src_pixels, kPixels * 3);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(dst_pixels_opt, kPixels * 3);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
   MemRandomize(dst_pixels_c, kPixels * 3);
+  MemRandomize(dst_pixels_opt, kPixels * 3);
 
   MaskCpuFlags(disable_cpu_flags_);
-  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_r,
-                benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                benchmark_width_, benchmark_width_, benchmark_height_);
-  MergeRGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                tmp_pixels_b, benchmark_width_, dst_pixels_c,
-                benchmark_width_ * 3, benchmark_width_, benchmark_height_);
+  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_c_r,
+                benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                tmp_pixels_c_b, benchmark_width_, benchmark_width_,
+                benchmark_height_);
+  MergeRGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                benchmark_width_, tmp_pixels_c_b, benchmark_width_,
+                dst_pixels_c, benchmark_width_ * 3, benchmark_width_,
+                benchmark_height_);
   MaskCpuFlags(benchmark_cpu_info_);
 
-  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_r,
-                benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                benchmark_width_, benchmark_width_, benchmark_height_);
+  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_opt_r,
+                benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                tmp_pixels_opt_b, benchmark_width_, benchmark_width_,
+                benchmark_height_);
 
   for (int i = 0; i < benchmark_iterations_; ++i) {
-    MergeRGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g,
-                  benchmark_width_, tmp_pixels_b, benchmark_width_,
+    MergeRGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                  benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
                   dst_pixels_opt, benchmark_width_ * 3, benchmark_width_,
                   benchmark_height_);
   }
@@ -3184,99 +3209,122 @@
   }
 
   free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
-  free_aligned_buffer_page_end(dst_pixels_opt);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
   free_aligned_buffer_page_end(dst_pixels_c);
+  free_aligned_buffer_page_end(dst_pixels_opt);
 }
 
 TEST_F(LibYUVPlanarTest, SplitRGBPlane_Opt) {
   // Round count up to multiple of 16
   const int kPixels = benchmark_width_ * benchmark_height_;
   align_buffer_page_end(src_pixels, kPixels * 3);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(dst_pixels_opt, kPixels * 3);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
   align_buffer_page_end(dst_pixels_c, kPixels * 3);
+  align_buffer_page_end(dst_pixels_opt, kPixels * 3);
 
   MemRandomize(src_pixels, kPixels * 3);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(dst_pixels_opt, kPixels * 3);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
   MemRandomize(dst_pixels_c, kPixels * 3);
+  MemRandomize(dst_pixels_opt, kPixels * 3);
 
   MaskCpuFlags(disable_cpu_flags_);
-  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_r,
-                benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                benchmark_width_, benchmark_width_, benchmark_height_);
-  MergeRGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                tmp_pixels_b, benchmark_width_, dst_pixels_c,
-                benchmark_width_ * 3, benchmark_width_, benchmark_height_);
+  SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_c_r,
+                benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                tmp_pixels_c_b, benchmark_width_, benchmark_width_,
+                benchmark_height_);
+  MergeRGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                benchmark_width_, tmp_pixels_c_b, benchmark_width_,
+                dst_pixels_c, benchmark_width_ * 3, benchmark_width_,
+                benchmark_height_);
   MaskCpuFlags(benchmark_cpu_info_);
 
   for (int i = 0; i < benchmark_iterations_; ++i) {
-    SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_r,
-                  benchmark_width_, tmp_pixels_g, benchmark_width_,
-                  tmp_pixels_b, benchmark_width_, benchmark_width_,
+    SplitRGBPlane(src_pixels, benchmark_width_ * 3, tmp_pixels_opt_r,
+                  benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                  tmp_pixels_opt_b, benchmark_width_, benchmark_width_,
                   benchmark_height_);
   }
-  MergeRGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                tmp_pixels_b, benchmark_width_, dst_pixels_opt,
-                benchmark_width_ * 3, benchmark_width_, benchmark_height_);
+  MergeRGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
+                dst_pixels_opt, benchmark_width_ * 3, benchmark_width_,
+                benchmark_height_);
 
   for (int i = 0; i < kPixels * 3; ++i) {
     EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
   }
 
   free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
-  free_aligned_buffer_page_end(dst_pixels_opt);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
   free_aligned_buffer_page_end(dst_pixels_c);
+  free_aligned_buffer_page_end(dst_pixels_opt);
 }
 
 TEST_F(LibYUVPlanarTest, MergeARGBPlane_Opt) {
   const int kPixels = benchmark_width_ * benchmark_height_;
   align_buffer_page_end(src_pixels, kPixels * 4);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(tmp_pixels_a, kPixels);
-  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
+  align_buffer_page_end(tmp_pixels_c_a, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_a, kPixels);
   align_buffer_page_end(dst_pixels_c, kPixels * 4);
+  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
 
   MemRandomize(src_pixels, kPixels * 4);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(tmp_pixels_a, kPixels);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
+  MemRandomize(tmp_pixels_c_a, kPixels);
+  MemRandomize(tmp_pixels_opt_a, kPixels);
   MemRandomize(dst_pixels_opt, kPixels * 4);
   MemRandomize(dst_pixels_c, kPixels * 4);
 
   MaskCpuFlags(disable_cpu_flags_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, tmp_pixels_a, benchmark_width_,
-                 benchmark_width_, benchmark_height_);
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, tmp_pixels_a, benchmark_width_,
-                 dst_pixels_c, benchmark_width_ * 4, benchmark_width_,
-                 benchmark_height_);
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
+                 benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                 tmp_pixels_c_b, benchmark_width_, tmp_pixels_c_a,
+                 benchmark_width_, benchmark_width_, benchmark_height_);
+  MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                 benchmark_width_, tmp_pixels_c_b, benchmark_width_,
+                 tmp_pixels_c_a, benchmark_width_, dst_pixels_c,
+                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
 
   MaskCpuFlags(benchmark_cpu_info_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, tmp_pixels_a, benchmark_width_,
-                 benchmark_width_, benchmark_height_);
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
+                 benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                 tmp_pixels_opt_b, benchmark_width_, tmp_pixels_opt_a,
+                 benchmark_width_, benchmark_width_, benchmark_height_);
 
   for (int i = 0; i < benchmark_iterations_; ++i) {
-    MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g,
-                   benchmark_width_, tmp_pixels_b, benchmark_width_,
-                   tmp_pixels_a, benchmark_width_, dst_pixels_opt,
+    MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                   benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
+                   tmp_pixels_opt_a, benchmark_width_, dst_pixels_opt,
                    benchmark_width_ * 4, benchmark_width_, benchmark_height_);
   }
 
@@ -3285,10 +3333,14 @@
   }
 
   free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
-  free_aligned_buffer_page_end(tmp_pixels_a);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
+  free_aligned_buffer_page_end(tmp_pixels_c_a);
+  free_aligned_buffer_page_end(tmp_pixels_opt_a);
   free_aligned_buffer_page_end(dst_pixels_opt);
   free_aligned_buffer_page_end(dst_pixels_c);
 }
@@ -3296,41 +3348,171 @@
 TEST_F(LibYUVPlanarTest, SplitARGBPlane_Opt) {
   const int kPixels = benchmark_width_ * benchmark_height_;
   align_buffer_page_end(src_pixels, kPixels * 4);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(tmp_pixels_a, kPixels);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
+  align_buffer_page_end(tmp_pixels_c_a, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_a, kPixels);
   align_buffer_page_end(dst_pixels_opt, kPixels * 4);
   align_buffer_page_end(dst_pixels_c, kPixels * 4);
 
   MemRandomize(src_pixels, kPixels * 4);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(tmp_pixels_a, kPixels);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
+  MemRandomize(tmp_pixels_c_a, kPixels);
+  MemRandomize(tmp_pixels_opt_a, kPixels);
   MemRandomize(dst_pixels_opt, kPixels * 4);
   MemRandomize(dst_pixels_c, kPixels * 4);
 
   MaskCpuFlags(disable_cpu_flags_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, tmp_pixels_a, benchmark_width_,
-                 benchmark_width_, benchmark_height_);
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, tmp_pixels_a, benchmark_width_,
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
+                 benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                 tmp_pixels_c_b, benchmark_width_, tmp_pixels_c_a,
+                 benchmark_width_, benchmark_width_, benchmark_height_);
+  MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                 benchmark_width_, tmp_pixels_c_b, benchmark_width_,
+                 tmp_pixels_c_a, benchmark_width_, dst_pixels_c,
+                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
+
+  MaskCpuFlags(benchmark_cpu_info_);
+  for (int i = 0; i < benchmark_iterations_; ++i) {
+    SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
+                   benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                   tmp_pixels_opt_b, benchmark_width_, tmp_pixels_opt_a,
+                   benchmark_width_, benchmark_width_, benchmark_height_);
+  }
+
+  MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                 benchmark_width_, tmp_pixels_opt_b, benchmark_width_,
+                 tmp_pixels_opt_a, benchmark_width_, dst_pixels_opt,
+                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
+
+  for (int i = 0; i < kPixels * 4; ++i) {
+    EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
+  }
+
+  free_aligned_buffer_page_end(src_pixels);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
+  free_aligned_buffer_page_end(tmp_pixels_c_a);
+  free_aligned_buffer_page_end(tmp_pixels_opt_a);
+  free_aligned_buffer_page_end(dst_pixels_c);
+  free_aligned_buffer_page_end(dst_pixels_opt);
+}
+
+TEST_F(LibYUVPlanarTest, MergeXRGBPlane_Opt) {
+  const int kPixels = benchmark_width_ * benchmark_height_;
+  align_buffer_page_end(src_pixels, kPixels * 4);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
+  align_buffer_page_end(dst_pixels_c, kPixels * 4);
+  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
+
+  MemRandomize(src_pixels, kPixels * 4);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
+  MemRandomize(dst_pixels_c, kPixels * 4);
+  MemRandomize(dst_pixels_opt, kPixels * 4);
+
+  MaskCpuFlags(disable_cpu_flags_);
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
+                 benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                 tmp_pixels_c_b, benchmark_width_, NULL, 0, benchmark_width_,
+                 benchmark_height_);
+  MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                 benchmark_width_, tmp_pixels_c_b, benchmark_width_, NULL, 0,
+                 dst_pixels_c, benchmark_width_ * 4, benchmark_width_,
+                 benchmark_height_);
+
+  MaskCpuFlags(benchmark_cpu_info_);
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
+                 benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                 tmp_pixels_opt_b, benchmark_width_, NULL, 0, benchmark_width_,
+                 benchmark_height_);
+
+  for (int i = 0; i < benchmark_iterations_; ++i) {
+    MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                   benchmark_width_, tmp_pixels_opt_b, benchmark_width_, NULL,
+                   0, dst_pixels_opt, benchmark_width_ * 4, benchmark_width_,
+                   benchmark_height_);
+  }
+
+  for (int i = 0; i < kPixels * 4; ++i) {
+    EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
+  }
+
+  free_aligned_buffer_page_end(src_pixels);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
+  free_aligned_buffer_page_end(dst_pixels_c);
+  free_aligned_buffer_page_end(dst_pixels_opt);
+}
+
+TEST_F(LibYUVPlanarTest, SplitXRGBPlane_Opt) {
+  const int kPixels = benchmark_width_ * benchmark_height_;
+  align_buffer_page_end(src_pixels, kPixels * 4);
+  align_buffer_page_end(tmp_pixels_c_r, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_r, kPixels);
+  align_buffer_page_end(tmp_pixels_c_g, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_g, kPixels);
+  align_buffer_page_end(tmp_pixels_c_b, kPixels);
+  align_buffer_page_end(tmp_pixels_opt_b, kPixels);
+  align_buffer_page_end(dst_pixels_c, kPixels * 4);
+  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
+
+  MemRandomize(src_pixels, kPixels * 4);
+  MemRandomize(tmp_pixels_c_r, kPixels);
+  MemRandomize(tmp_pixels_opt_r, kPixels);
+  MemRandomize(tmp_pixels_c_g, kPixels);
+  MemRandomize(tmp_pixels_opt_g, kPixels);
+  MemRandomize(tmp_pixels_c_b, kPixels);
+  MemRandomize(tmp_pixels_opt_b, kPixels);
+  MemRandomize(dst_pixels_c, kPixels * 4);
+  MemRandomize(dst_pixels_opt, kPixels * 4);
+
+  MaskCpuFlags(disable_cpu_flags_);
+  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_c_r,
+                 benchmark_width_, tmp_pixels_c_g, benchmark_width_,
+                 tmp_pixels_c_b, benchmark_width_, NULL, 0, benchmark_width_,
+                 benchmark_height_);
+  MergeARGBPlane(tmp_pixels_c_r, benchmark_width_, tmp_pixels_c_g,
+                 benchmark_width_, tmp_pixels_c_b, benchmark_width_, NULL, 0,
                  dst_pixels_c, benchmark_width_ * 4, benchmark_width_,
                  benchmark_height_);
 
   MaskCpuFlags(benchmark_cpu_info_);
   for (int i = 0; i < benchmark_iterations_; ++i) {
-    SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                   benchmark_width_, tmp_pixels_g, benchmark_width_,
-                   tmp_pixels_b, benchmark_width_, tmp_pixels_a,
-                   benchmark_width_, benchmark_width_, benchmark_height_);
+    SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_opt_r,
+                   benchmark_width_, tmp_pixels_opt_g, benchmark_width_,
+                   tmp_pixels_opt_b, benchmark_width_, NULL, 0,
+                   benchmark_width_, benchmark_height_);
   }
 
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, tmp_pixels_a, benchmark_width_,
+  MergeARGBPlane(tmp_pixels_opt_r, benchmark_width_, tmp_pixels_opt_g,
+                 benchmark_width_, tmp_pixels_opt_b, benchmark_width_, NULL, 0,
                  dst_pixels_opt, benchmark_width_ * 4, benchmark_width_,
                  benchmark_height_);
 
@@ -3339,111 +3521,14 @@
   }
 
   free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
-  free_aligned_buffer_page_end(tmp_pixels_a);
-  free_aligned_buffer_page_end(dst_pixels_opt);
+  free_aligned_buffer_page_end(tmp_pixels_c_r);
+  free_aligned_buffer_page_end(tmp_pixels_opt_r);
+  free_aligned_buffer_page_end(tmp_pixels_c_g);
+  free_aligned_buffer_page_end(tmp_pixels_opt_g);
+  free_aligned_buffer_page_end(tmp_pixels_c_b);
+  free_aligned_buffer_page_end(tmp_pixels_opt_b);
   free_aligned_buffer_page_end(dst_pixels_c);
-}
-
-TEST_F(LibYUVPlanarTest, MergeXRGBPlane_Opt) {
-  const int kPixels = benchmark_width_ * benchmark_height_;
-  align_buffer_page_end(src_pixels, kPixels * 4);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
-  align_buffer_page_end(dst_pixels_c, kPixels * 4);
-
-  MemRandomize(src_pixels, kPixels * 4);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(dst_pixels_opt, kPixels * 4);
-  MemRandomize(dst_pixels_c, kPixels * 4);
-
-  MaskCpuFlags(disable_cpu_flags_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, NULL, 0, benchmark_width_,
-                 benchmark_height_);
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, NULL, 0, dst_pixels_c,
-                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
-
-  MaskCpuFlags(benchmark_cpu_info_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, NULL, 0, benchmark_width_,
-                 benchmark_height_);
-
-  for (int i = 0; i < benchmark_iterations_; ++i) {
-    MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g,
-                   benchmark_width_, tmp_pixels_b, benchmark_width_, NULL, 0,
-                   dst_pixels_opt, benchmark_width_ * 4, benchmark_width_,
-                   benchmark_height_);
-  }
-
-  for (int i = 0; i < kPixels * 4; ++i) {
-    EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
-  }
-
-  free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
   free_aligned_buffer_page_end(dst_pixels_opt);
-  free_aligned_buffer_page_end(dst_pixels_c);
-}
-
-TEST_F(LibYUVPlanarTest, SplitXRGBPlane_Opt) {
-  const int kPixels = benchmark_width_ * benchmark_height_;
-  align_buffer_page_end(src_pixels, kPixels * 4);
-  align_buffer_page_end(tmp_pixels_r, kPixels);
-  align_buffer_page_end(tmp_pixels_g, kPixels);
-  align_buffer_page_end(tmp_pixels_b, kPixels);
-  align_buffer_page_end(dst_pixels_opt, kPixels * 4);
-  align_buffer_page_end(dst_pixels_c, kPixels * 4);
-
-  MemRandomize(src_pixels, kPixels * 4);
-  MemRandomize(tmp_pixels_r, kPixels);
-  MemRandomize(tmp_pixels_g, kPixels);
-  MemRandomize(tmp_pixels_b, kPixels);
-  MemRandomize(dst_pixels_opt, kPixels * 4);
-  MemRandomize(dst_pixels_c, kPixels * 4);
-
-  MaskCpuFlags(disable_cpu_flags_);
-  SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                 benchmark_width_, tmp_pixels_g, benchmark_width_, tmp_pixels_b,
-                 benchmark_width_, NULL, 0, benchmark_width_,
-                 benchmark_height_);
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, NULL, 0, dst_pixels_c,
-                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
-
-  MaskCpuFlags(benchmark_cpu_info_);
-  for (int i = 0; i < benchmark_iterations_; ++i) {
-    SplitARGBPlane(src_pixels, benchmark_width_ * 4, tmp_pixels_r,
-                   benchmark_width_, tmp_pixels_g, benchmark_width_,
-                   tmp_pixels_b, benchmark_width_, NULL, 0, benchmark_width_,
-                   benchmark_height_);
-  }
-
-  MergeARGBPlane(tmp_pixels_r, benchmark_width_, tmp_pixels_g, benchmark_width_,
-                 tmp_pixels_b, benchmark_width_, NULL, 0, dst_pixels_opt,
-                 benchmark_width_ * 4, benchmark_width_, benchmark_height_);
-
-  for (int i = 0; i < kPixels * 4; ++i) {
-    EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]);
-  }
-
-  free_aligned_buffer_page_end(src_pixels);
-  free_aligned_buffer_page_end(tmp_pixels_r);
-  free_aligned_buffer_page_end(tmp_pixels_g);
-  free_aligned_buffer_page_end(tmp_pixels_b);
-  free_aligned_buffer_page_end(dst_pixels_opt);
-  free_aligned_buffer_page_end(dst_pixels_c);
 }
 
 // Merge 4 channels
@@ -3717,6 +3802,37 @@
   free_aligned_buffer_page_end(dst_pixels_y_c);
 }
 
+TEST_F(LibYUVPlanarTest, Convert8To8Plane) {
+  const int kPixels = benchmark_width_ * benchmark_height_;
+  align_buffer_page_end(src_pixels_y, kPixels);
+  align_buffer_page_end(dst_pixels_y_opt, kPixels);
+  align_buffer_page_end(dst_pixels_y_c, kPixels);
+
+  MemRandomize(src_pixels_y, kPixels);
+  memset(dst_pixels_y_opt, 0, kPixels);
+  memset(dst_pixels_y_c, 1, kPixels);
+
+  MaskCpuFlags(disable_cpu_flags_);
+  Convert8To8Plane(src_pixels_y, benchmark_width_, dst_pixels_y_c,
+                   benchmark_width_, 220, 16, benchmark_width_,
+                   benchmark_height_);
+  MaskCpuFlags(benchmark_cpu_info_);
+
+  for (int i = 0; i < benchmark_iterations_; ++i) {
+    Convert8To8Plane(src_pixels_y, benchmark_width_, dst_pixels_y_opt,
+                     benchmark_width_, 220, 16, benchmark_width_,
+                     benchmark_height_);
+  }
+
+  for (int i = 0; i < kPixels; ++i) {
+    EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
+  }
+
+  free_aligned_buffer_page_end(src_pixels_y);
+  free_aligned_buffer_page_end(dst_pixels_y_opt);
+  free_aligned_buffer_page_end(dst_pixels_y_c);
+}
+
 TEST_F(LibYUVPlanarTest, YUY2ToY) {
   const int kPixels = benchmark_width_ * benchmark_height_;
   align_buffer_page_end(src_pixels_y, kPixels * 2);
@@ -4437,15 +4553,11 @@
   int dst_height = (benchmark_height_ + 1) / 2;
   align_buffer_page_end(src_pixels_u, benchmark_width_ * benchmark_height_);
   align_buffer_page_end(src_pixels_v, benchmark_width_ * benchmark_height_);
-  align_buffer_page_end(tmp_pixels_u, dst_width * dst_height);
-  align_buffer_page_end(tmp_pixels_v, dst_width * dst_height);
   align_buffer_page_end(dst_pixels_uv_opt, dst_width * 2 * dst_height);
   align_buffer_page_end(dst_pixels_uv_c, dst_width * 2 * dst_height);
 
   MemRandomize(src_pixels_u, benchmark_width_ * benchmark_height_);
   MemRandomize(src_pixels_v, benchmark_width_ * benchmark_height_);
-  MemRandomize(tmp_pixels_u, dst_width * dst_height);
-  MemRandomize(tmp_pixels_v, dst_width * dst_height);
   MemRandomize(dst_pixels_uv_opt, dst_width * 2 * dst_height);
   MemRandomize(dst_pixels_uv_c, dst_width * 2 * dst_height);
 
@@ -4467,8 +4579,6 @@
 
   free_aligned_buffer_page_end(src_pixels_u);
   free_aligned_buffer_page_end(src_pixels_v);
-  free_aligned_buffer_page_end(tmp_pixels_u);
-  free_aligned_buffer_page_end(tmp_pixels_v);
   free_aligned_buffer_page_end(dst_pixels_uv_opt);
   free_aligned_buffer_page_end(dst_pixels_uv_c);
 }
diff --git a/unit_test/rotate_argb_test.cc b/unit_test/rotate_argb_test.cc
index 74952c4..4c7b0b2 100644
--- a/unit_test/rotate_argb_test.cc
+++ b/unit_test/rotate_argb_test.cc
@@ -16,15 +16,15 @@
 
 namespace libyuv {
 
-void TestRotateBpp(int src_width,
-                   int src_height,
-                   int dst_width,
-                   int dst_height,
-                   libyuv::RotationMode mode,
-                   int benchmark_iterations,
-                   int disable_cpu_flags,
-                   int benchmark_cpu_info,
-                   const int kBpp) {
+static void TestRotateBpp(int src_width,
+                          int src_height,
+                          int dst_width,
+                          int dst_height,
+                          libyuv::RotationMode mode,
+                          int benchmark_iterations,
+                          int disable_cpu_flags,
+                          int benchmark_cpu_info,
+                          const int kBpp) {
   if (src_width < 1) {
     src_width = 1;
   }
diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc
index f54a68f..66fd4cf 100644
--- a/unit_test/scale_argb_test.cc
+++ b/unit_test/scale_argb_test.cc
@@ -320,16 +320,18 @@
 
 #ifndef DISABLE_SLOW_TESTS
 // Test scale to a specified size with all 4 filters.
-#define TEST_SCALETO(name, width, height)         \
-  TEST_SCALETO1(, name, width, height, None, 0)   \
-  TEST_SCALETO1(, name, width, height, Linear, 3) \
-  TEST_SCALETO1(, name, width, height, Bilinear, 3)
+#define TEST_SCALETO(name, width, height)           \
+  TEST_SCALETO1(, name, width, height, None, 0)     \
+  TEST_SCALETO1(, name, width, height, Linear, 3)   \
+  TEST_SCALETO1(, name, width, height, Bilinear, 3) \
+  TEST_SCALETO1(, name, width, height, Box, 3)
 #else
 #if defined(ENABLE_FULL_TESTS)
-#define TEST_SCALETO(name, width, height)                  \
-  TEST_SCALETO1(DISABLED_, name, width, height, None, 0)   \
-  TEST_SCALETO1(DISABLED_, name, width, height, Linear, 3) \
-  TEST_SCALETO1(DISABLED_, name, width, height, Bilinear, 3)
+#define TEST_SCALETO(name, width, height)                    \
+  TEST_SCALETO1(DISABLED_, name, width, height, None, 0)     \
+  TEST_SCALETO1(DISABLED_, name, width, height, Linear, 3)   \
+  TEST_SCALETO1(DISABLED_, name, width, height, Bilinear, 3) \
+  TEST_SCALETO1(DISABLED_, name, width, height, Box, 3)
 #else
 #define TEST_SCALETO(name, width, height) \
   TEST_SCALETO1(DISABLED_, name, width, height, Bilinear, 3)
@@ -340,6 +342,7 @@
 TEST_SCALETO(ARGBScale, 569, 480)
 TEST_SCALETO(ARGBScale, 640, 360)
 #ifndef DISABLE_SLOW_TESTS
+TEST_SCALETO(ARGBScale, 50, 1)
 TEST_SCALETO(ARGBScale, 256, 144) /* 128x72 * 2 */
 TEST_SCALETO(ARGBScale, 320, 240)
 TEST_SCALETO(ARGBScale, 1280, 720)
@@ -369,26 +372,25 @@
 
 // Scale with YUV conversion to ARGB and clipping.
 // TODO(fbarchard): Add fourcc support.  All 4 ARGB formats is easy to support.
-LIBYUV_API
-int YUVToARGBScaleReference2(const uint8_t* src_y,
-                             int src_stride_y,
-                             const uint8_t* src_u,
-                             int src_stride_u,
-                             const uint8_t* src_v,
-                             int src_stride_v,
-                             uint32_t /* src_fourcc */,
-                             int src_width,
-                             int src_height,
-                             uint8_t* dst_argb,
-                             int dst_stride_argb,
-                             uint32_t /* dst_fourcc */,
-                             int dst_width,
-                             int dst_height,
-                             int clip_x,
-                             int clip_y,
-                             int clip_width,
-                             int clip_height,
-                             enum FilterMode filtering) {
+static int YUVToARGBScaleReference2(const uint8_t* src_y,
+                                    int src_stride_y,
+                                    const uint8_t* src_u,
+                                    int src_stride_u,
+                                    const uint8_t* src_v,
+                                    int src_stride_v,
+                                    uint32_t /* src_fourcc */,
+                                    int src_width,
+                                    int src_height,
+                                    uint8_t* dst_argb,
+                                    int dst_stride_argb,
+                                    uint32_t /* dst_fourcc */,
+                                    int dst_width,
+                                    int dst_height,
+                                    int clip_x,
+                                    int clip_y,
+                                    int clip_width,
+                                    int clip_height,
+                                    enum FilterMode filtering) {
   uint8_t* argb_buffer =
       static_cast<uint8_t*>(malloc(src_width * src_height * 4));
   int r;
diff --git a/unit_test/scale_plane_test.cc b/unit_test/scale_plane_test.cc
index 9ce47a0..3df71a5 100644
--- a/unit_test/scale_plane_test.cc
+++ b/unit_test/scale_plane_test.cc
@@ -128,11 +128,6 @@
 }
 #endif  // HAS_SCALEROWDOWN2_SSSE3
 
-extern "C" void ScaleRowDown2Box_16_NEON(const uint16_t* src_ptr,
-                                         ptrdiff_t src_stride,
-                                         uint16_t* dst,
-                                         int dst_width);
-
 TEST_F(LibYUVScaleTest, TestScaleRowDown2Box_16) {
   SIMD_ALIGNED(uint16_t orig_pixels[2560 * 2]);
   SIMD_ALIGNED(uint16_t dst_pixels_c[1280]);
diff --git a/unit_test/scale_test.cc b/unit_test/scale_test.cc
index 6e3b927..fd8fff8 100644
--- a/unit_test/scale_test.cc
+++ b/unit_test/scale_test.cc
@@ -1053,10 +1053,12 @@
 TEST_SCALETO(Scale, 640, 360)
 #ifndef DISABLE_SLOW_TESTS
 TEST_SCALETO(Scale, 256, 144) /* 128x72 * 2 */
+TEST_SCALETO(Scale, 264, 216)
 TEST_SCALETO(Scale, 320, 240)
 TEST_SCALETO(Scale, 1280, 720)
 TEST_SCALETO(Scale, 1920, 1080)
-#endif  // DISABLE_SLOW_TESTS
+TEST_SCALETO(Scale, 1080, 1920)  // for rotated phones
+#endif                           // DISABLE_SLOW_TESTS
 #undef TEST_SCALETO1
 #undef TEST_SCALETO
 
diff --git a/unit_test/testdata/juno.txt b/unit_test/testdata/juno.txt
deleted file mode 100644
index dd46527..0000000
--- a/unit_test/testdata/juno.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Processor       : AArch64 Processor rev 0 (aarch64)
-processor       : 0
-processor       : 1
-processor       : 2
-processor       : 3
-processor       : 4
-processor       : 5
-Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32
-CPU implementer : 0x41
-CPU architecture: AArch64
-CPU variant     : 0x0
-CPU part        : 0xd07
-CPU revision    : 0
-
-Hardware        : Juno
diff --git a/unit_test/unit_test.cc b/unit_test/unit_test.cc
index 239d5b9..d917f53 100644
--- a/unit_test/unit_test.cc
+++ b/unit_test/unit_test.cc
@@ -67,12 +67,29 @@
 }
 #endif
 
-int TestCpuEnv(int cpu_info) {
+static int TestCpuEnv(int cpu_info) {
 #if defined(__arm__) || defined(__aarch64__)
   if (TestEnv("LIBYUV_DISABLE_NEON")) {
     cpu_info &= ~libyuv::kCpuHasNEON;
   }
 #endif
+#if defined(__aarch64__)
+  if (TestEnv("LIBYUV_DISABLE_NEON_DOTPROD")) {
+    cpu_info &= ~libyuv::kCpuHasNeonDotProd;
+  }
+  if (TestEnv("LIBYUV_DISABLE_NEON_I8MM")) {
+    cpu_info &= ~libyuv::kCpuHasNeonI8MM;
+  }
+  if (TestEnv("LIBYUV_DISABLE_SVE")) {
+    cpu_info &= ~libyuv::kCpuHasSVE;
+  }
+  if (TestEnv("LIBYUV_DISABLE_SVE2")) {
+    cpu_info &= ~libyuv::kCpuHasSVE2;
+  }
+  if (TestEnv("LIBYUV_DISABLE_SME")) {
+    cpu_info &= ~libyuv::kCpuHasSME;
+  }
+#endif
 #if defined(__mips__) && defined(__linux__)
   if (TestEnv("LIBYUV_DISABLE_MSA")) {
     cpu_info &= ~libyuv::kCpuHasMSA;
@@ -147,12 +164,18 @@
   if (TestEnv("LIBYUV_DISABLE_AVX10")) {
     cpu_info &= ~libyuv::kCpuHasAVX10;
   }
+  if (TestEnv("LIBYUV_DISABLE_AVX10_2")) {
+    cpu_info &= ~libyuv::kCpuHasAVX10_2;
+  }
   if (TestEnv("LIBYUV_DISABLE_AVXVNNI")) {
     cpu_info &= ~libyuv::kCpuHasAVXVNNI;
   }
   if (TestEnv("LIBYUV_DISABLE_AVXVNNIINT8")) {
     cpu_info &= ~libyuv::kCpuHasAVXVNNIINT8;
   }
+  if (TestEnv("LIBYUV_DISABLE_AMXINT8")) {
+    cpu_info &= ~libyuv::kCpuHasAMXINT8;
+  }
 #endif
   if (TestEnv("LIBYUV_DISABLE_ASM")) {
     cpu_info = libyuv::kCpuInitialized;
@@ -204,7 +227,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -260,7 +283,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -316,7 +339,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -372,7 +395,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -428,7 +451,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -484,7 +507,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
@@ -540,7 +563,7 @@
   }
   const char* cpu_info = getenv("LIBYUV_CPU_INFO");
   if (cpu_info) {
-    benchmark_cpu_info_ = atoi(cpu_flags);  // NOLINT
+    benchmark_cpu_info_ = atoi(cpu_info);  // NOLINT
   }
   if (LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info)) {
     benchmark_cpu_info_ = LIBYUV_GET_FLAG(FLAGS_libyuv_cpu_info);
diff --git a/unit_test/unit_test.h b/unit_test/unit_test.h
index 99cc8d1..7440cc7 100644
--- a/unit_test/unit_test.h
+++ b/unit_test/unit_test.h
@@ -70,9 +70,11 @@
 }
 
 #define align_buffer_page_end(var, size)                                \
+  uint8_t* var = NULL;                                                  \
   uint8_t* var##_mem =                                                  \
       reinterpret_cast<uint8_t*>(malloc(((size) + 4095 + 63) & ~4095)); \
-  uint8_t* var = reinterpret_cast<uint8_t*>(                            \
+  if (var##_mem)                                                        \
+  var = reinterpret_cast<uint8_t*>(                                     \
       (intptr_t)(var##_mem + (((size) + 4095 + 63) & ~4095) - (size)) & ~63)
 
 #define free_aligned_buffer_page_end(var) \
@@ -80,9 +82,11 @@
   var = NULL
 
 #define align_buffer_page_end_16(var, size)                                 \
+  uint16_t* var = NULL;                                                     \
   uint8_t* var##_mem =                                                      \
       reinterpret_cast<uint8_t*>(malloc(((size)*2 + 4095 + 63) & ~4095));   \
-  uint16_t* var = reinterpret_cast<uint16_t*>(                              \
+  if (var##_mem)                                                            \
+  var = reinterpret_cast<uint16_t*>(                                        \
       (intptr_t)(var##_mem + (((size)*2 + 4095 + 63) & ~4095) - (size)*2) & \
       ~63)
 
diff --git a/util/cpuid.c b/util/cpuid.c
index c07e6e9..0f54b42 100644
--- a/util/cpuid.c
+++ b/util/cpuid.c
@@ -12,24 +12,126 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef __linux__
+#include <ctype.h>
+#include <sys/utsname.h>
+#endif
+
 #include "libyuv/cpu_id.h"
 
 #ifdef __cplusplus
 using namespace libyuv;
 #endif
 
+#ifdef __linux__
+static void KernelVersion(int *version) {
+  struct utsname buffer;
+  int i = 0;
+
+  version[0] = version[1] = 0;
+  if (uname(&buffer) == 0) {
+    char *v = buffer.release;
+    for (i = 0; *v && i < 2; ++v) {
+      if (isdigit(*v)) {
+        version[i++] = (int) strtol(v, &v, 10);
+      }
+    }
+  }
+}
+#endif
+
 int main(int argc, const char* argv[]) {
-  int cpu_flags = TestCpuFlag(-1);
-  int has_arm = TestCpuFlag(kCpuHasARM);
-  int has_riscv = TestCpuFlag(kCpuHasRISCV);
-  int has_x86 = TestCpuFlag(kCpuHasX86);
-  int has_mips = TestCpuFlag(kCpuHasMIPS);
-  int has_loongarch = TestCpuFlag(kCpuHasLOONGARCH);
   (void)argc;
   (void)argv;
 
+#if defined(__linux__)
+  {
+    int kernelversion[2];
+    KernelVersion(kernelversion);
+    printf("Kernel Version %d.%d\n", kernelversion[0], kernelversion[1]);
+  }
+#endif  // defined(__linux__)
+
+#if defined(__arm__) || defined(__aarch64__)
+  int has_arm = TestCpuFlag(kCpuHasARM);
+  if (has_arm) {
+    int has_neon = TestCpuFlag(kCpuHasNEON);
+    int has_neon_dotprod = TestCpuFlag(kCpuHasNeonDotProd);
+    int has_neon_i8mm = TestCpuFlag(kCpuHasNeonI8MM);
+    int has_sve = TestCpuFlag(kCpuHasSVE);
+    int has_sve2 = TestCpuFlag(kCpuHasSVE2);
+    int has_sme = TestCpuFlag(kCpuHasSME);
+    printf("Has Arm 0x%x\n", has_arm);
+    printf("Has Neon 0x%x\n", has_neon);
+    printf("Has Neon DotProd 0x%x\n", has_neon_dotprod);
+    printf("Has Neon I8MM 0x%x\n", has_neon_i8mm);
+    printf("Has SVE 0x%x\n", has_sve);
+    printf("Has SVE2 0x%x\n", has_sve2);
+    printf("Has SME 0x%x\n", has_sme);
+
+#if __aarch64__
+    // Read and print the SVE and SME vector lengths.
+    if (has_sve) {
+      int sve_vl;
+      __asm__(".inst 0x04bf5020    \n"  // rdvl x0, #1
+          "mov %w[sve_vl], w0  \n"
+          : [sve_vl] "=r"(sve_vl)  // %[sve_vl]
+          :
+          : "x0");
+      printf("SVE vector length: %d bytes\n", sve_vl);
+    }
+    if (has_sme) {
+      int sme_vl;
+      __asm__(".inst 0x04bf5820    \n"  // rdsvl x0, #1
+          "mov %w[sme_vl], w0  \n"
+          : [sme_vl] "=r"(sme_vl)  // %[sme_vl]
+          :
+          : "x0");
+      printf("SME vector length: %d bytes\n", sme_vl);
+    }
+#endif  // defined(__aarch64__)
+  }
+#endif  // if defined(__arm__) || defined(__aarch64__)
+
+#if defined(__riscv)
+  int has_riscv = TestCpuFlag(kCpuHasRISCV);
+  if (has_riscv) {
+    int has_rvv = TestCpuFlag(kCpuHasRVV);
+    printf("Has RISCV 0x%x\n", has_riscv);
+    printf("Has RVV 0x%x\n", has_rvv);
+
+    // Read and print the RVV vector length.
+    if (has_rvv) {
+      register uint32_t vlenb __asm__ ("t0");
+      __asm__(".word 0xC22022F3"  /* CSRR t0, vlenb */ : "=r" (vlenb));
+      printf("RVV vector length: %d bytes\n", vlenb);
+    }
+  }
+#endif  // defined(__riscv)
+
+#if defined(__mips__)
+  int has_mips = TestCpuFlag(kCpuHasMIPS);
+  if (has_mips) {
+    int has_msa = TestCpuFlag(kCpuHasMSA);
+    printf("Has MIPS 0x%x\n", has_mips);
+    printf("Has MSA 0x%x\n", has_msa);
+  }
+#endif  // defined(__mips__)
+
+#if defined(__loongarch__)
+  int has_loongarch = TestCpuFlag(kCpuHasLOONGARCH);
+  if (has_loongarch) {
+    int has_lsx  = TestCpuFlag(kCpuHasLSX);
+    int has_lasx = TestCpuFlag(kCpuHasLASX);
+    printf("Has LOONGARCH 0x%x\n", has_loongarch);
+    printf("Has LSX 0x%x\n", has_lsx);
+    printf("Has LASX 0x%x\n", has_lasx);
+  }
+#endif  // defined(__loongarch__)
+
 #if defined(__i386__) || defined(__x86_64__) || \
     defined(_M_IX86) || defined(_M_X64)
+  int has_x86 = TestCpuFlag(kCpuHasX86);
   if (has_x86) {
     int family, model, cpu_info[4];
     // Vendor ID:
@@ -61,32 +163,7 @@
     model = ((cpu_info[0] >> 4) & 0x0f) | ((cpu_info[0] >> 12) & 0xf0);
     printf("Cpu Family %d (0x%x), Model %d (0x%x)\n", family, family,
            model, model);
-  }
-#endif
-  printf("Cpu Flags 0x%x\n", cpu_flags);
-  if (has_arm) {
-    int has_neon = TestCpuFlag(kCpuHasNEON);
-    printf("Has ARM 0x%x\n", has_arm);
-    printf("Has NEON 0x%x\n", has_neon);
-  }
-  if (has_riscv) {
-    int has_rvv = TestCpuFlag(kCpuHasRVV);
-    printf("Has RISCV 0x%x\n", has_riscv);
-    printf("Has RVV 0x%x\n", has_rvv);
-  }
-  if (has_mips) {
-    int has_msa = TestCpuFlag(kCpuHasMSA);
-    printf("Has MIPS 0x%x\n", has_mips);
-    printf("Has MSA 0x%x\n", has_msa);
-  }
-  if (has_loongarch) {
-    int has_lsx  = TestCpuFlag(kCpuHasLSX);
-    int has_lasx = TestCpuFlag(kCpuHasLASX);
-    printf("Has LOONGARCH 0x%x\n", has_loongarch);
-    printf("Has LSX 0x%x\n", has_lsx);
-    printf("Has LASX 0x%x\n", has_lasx);
-  }
-  if (has_x86) {
+
     int has_sse2 = TestCpuFlag(kCpuHasSSE2);
     int has_ssse3 = TestCpuFlag(kCpuHasSSSE3);
     int has_sse41 = TestCpuFlag(kCpuHasSSE41);
@@ -94,6 +171,7 @@
     int has_avx = TestCpuFlag(kCpuHasAVX);
     int has_avx2 = TestCpuFlag(kCpuHasAVX2);
     int has_erms = TestCpuFlag(kCpuHasERMS);
+    int has_fsmr = TestCpuFlag(kCpuHasFSMR);
     int has_fma3 = TestCpuFlag(kCpuHasFMA3);
     int has_f16c = TestCpuFlag(kCpuHasF16C);
     int has_avx512bw = TestCpuFlag(kCpuHasAVX512BW);
@@ -103,8 +181,10 @@
     int has_avx512vbmi2 = TestCpuFlag(kCpuHasAVX512VBMI2);
     int has_avx512vbitalg = TestCpuFlag(kCpuHasAVX512VBITALG);
     int has_avx10 = TestCpuFlag(kCpuHasAVX10);
+    int has_avx10_2 = TestCpuFlag(kCpuHasAVX10_2);
     int has_avxvnni = TestCpuFlag(kCpuHasAVXVNNI);
     int has_avxvnniint8 = TestCpuFlag(kCpuHasAVXVNNIINT8);
+    int has_amxint8 = TestCpuFlag(kCpuHasAMXINT8);
     printf("Has X86 0x%x\n", has_x86);
     printf("Has SSE2 0x%x\n", has_sse2);
     printf("Has SSSE3 0x%x\n", has_ssse3);
@@ -113,6 +193,7 @@
     printf("Has AVX 0x%x\n", has_avx);
     printf("Has AVX2 0x%x\n", has_avx2);
     printf("Has ERMS 0x%x\n", has_erms);
+    printf("Has FSMR 0x%x\n", has_fsmr);
     printf("Has FMA3 0x%x\n", has_fma3);
     printf("Has F16C 0x%x\n", has_f16c);
     printf("Has AVX512BW 0x%x\n", has_avx512bw);
@@ -122,9 +203,12 @@
     printf("Has AVX512VBMI2 0x%x\n", has_avx512vbmi2);
     printf("Has AVX512VBITALG 0x%x\n", has_avx512vbitalg);
     printf("Has AVX10 0x%x\n", has_avx10);
+    printf("Has AVX10_2 0x%x\n", has_avx10_2);
     printf("HAS AVXVNNI 0x%x\n", has_avxvnni);
     printf("Has AVXVNNIINT8 0x%x\n", has_avxvnniint8);
+    printf("Has AMXINT8 0x%x\n", has_amxint8);
   }
+#endif  // defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
   return 0;
 }
 
diff --git a/util/psnr_main.cc b/util/psnr_main.cc
index 8b9fd97..a11cd3f 100644
--- a/util/psnr_main.cc
+++ b/util/psnr_main.cc
@@ -65,9 +65,9 @@
 #endif
 
 // Parse PYUV format. ie name.1920x800_24Hz_P420.yuv
-bool ExtractResolutionFromFilename(const char* name,
-                                   int* width_ptr,
-                                   int* height_ptr) {
+static bool ExtractResolutionFromFilename(const char* name,
+                                          int* width_ptr,
+                                          int* height_ptr) {
   // Isolate the .width_height. section of the filename by searching for a
   // dot or underscore followed by a digit.
   for (int i = 0; name[i]; ++i) {
@@ -105,25 +105,12 @@
   return false;
 }
 
-// Scale Y channel from 16..240 to 0..255.
-// This can be useful when comparing codecs that are inconsistant about Y
-uint8_t ScaleY(uint8_t y) {
-  int ny = (y - 16) * 256 / 224;
-  if (ny < 0) {
-    ny = 0;
-  }
-  if (ny > 255) {
-    ny = 255;
-  }
-  return static_cast<uint8_t>(ny);
-}
-
 // MSE = Mean Square Error
-double GetMSE(double sse, double size) {
+static double GetMSE(double sse, double size) {
   return sse / size;
 }
 
-void PrintHelp(const char* program) {
+static void PrintHelp(const char* program) {
   printf("%s [-options] org_seq rec_seq [rec_seq2.. etc]\n", program);
 #ifdef HAVE_JPEG
   printf("jpeg or raw YUV 420 supported.\n");
@@ -151,7 +138,7 @@
   exit(0);
 }
 
-void ParseOptions(int argc, const char* argv[]) {
+static void ParseOptions(int argc, const char* argv[]) {
   if (argc <= 1) {
     PrintHelp(argv[0]);
   }
@@ -240,15 +227,15 @@
   }
 }
 
-bool UpdateMetrics(uint8_t* ch_org,
-                   uint8_t* ch_rec,
-                   const int y_size,
-                   const int uv_size,
-                   const size_t total_size,
-                   int number_of_frames,
-                   metric* cur_distortion_psnr,
-                   metric* distorted_frame,
-                   bool compute_psnr) {
+static bool UpdateMetrics(uint8_t* ch_org,
+                          uint8_t* ch_rec,
+                          const int y_size,
+                          const int uv_size,
+                          const size_t total_size,
+                          int number_of_frames,
+                          metric* cur_distortion_psnr,
+                          metric* distorted_frame,
+                          bool compute_psnr) {
   const int uv_offset = (do_swap_uv ? uv_size : 0);
   const uint8_t* const u_org = ch_org + y_size + uv_offset;
   const uint8_t* const u_rec = ch_rec + y_size;