Merge "Improved intrinsic version of vp8_denoiser_filter_neon"
diff --git a/build/make/Makefile b/build/make/Makefile
index dd7fb4a..c4d53f1 100644
--- a/build/make/Makefile
+++ b/build/make/Makefile
@@ -22,6 +22,7 @@
 install:: .DEFAULT
 test:: .DEFAULT
 testdata:: .DEFAULT
+utiltest: .DEFAULT
 
 
 # Note: md5sum is not installed on OS X, but openssl is. Openssl may not be
@@ -52,8 +53,6 @@
                 | sed -e 's/MD5(\(.*\))= \([0-9a-f]\{32\}\)/\2  \1/' \
                 > md5sums.txt;\
         fi
-
-
 endif
 
 ifneq ($(target),)
@@ -112,6 +111,8 @@
 test::
 .PHONY: testdata
 testdata::
+.PHONY: utiltest
+utiltest:
 
 # Add compiler flags for intrinsic files
 $(BUILD_PFX)%_mmx.c.d: CFLAGS += -mmmx
@@ -147,6 +148,15 @@
 	$(if $(quiet),@echo "    [CXX] $@")
 	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
 
+$(BUILD_PFX)%.cpp.d: %.cpp
+	$(if $(quiet),@echo "    [DEP] $@")
+	$(qexec)mkdir -p $(dir $@)
+	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@
+
+$(BUILD_PFX)%.cpp.o: %.cpp
+	$(if $(quiet),@echo "    [CXX] $@")
+	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
+
 $(BUILD_PFX)%.asm.d: %.asm
 	$(if $(quiet),@echo "    [DEP] $@")
 	$(qexec)mkdir -p $(dir $@)
@@ -218,7 +228,7 @@
 
 find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2)))))
 find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) )
-obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o
+obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o .cpp=.cpp.o
 objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) ))
 
 install_map_templates=$(eval $(call install_map_template,$(1),$(2)))
@@ -401,6 +411,7 @@
     DIST-SRCS-$(CONFIG_MSVS)  += build/make/gen_msvs_proj.sh
     DIST-SRCS-$(CONFIG_MSVS)  += build/make/gen_msvs_sln.sh
     DIST-SRCS-$(CONFIG_MSVS)  += build/make/gen_msvs_vcxproj.sh
+    DIST-SRCS-$(CONFIG_MSVS)  += build/make/msvs_common.sh
     DIST-SRCS-$(CONFIG_MSVS)  += build/x86-msvs/obj_int_extract.bat
     DIST-SRCS-$(CONFIG_MSVS)  += build/arm-msvs/obj_int_extract.bat
     DIST-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh
diff --git a/build/make/configure.sh b/build/make/configure.sh
index 514c442..a65d395 100755
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -864,7 +864,7 @@
             CC=armcc
             AR=armar
             AS=armasm
-            LD=${source_path}/build/make/armlink_adapter.sh
+            LD="${source_path}/build/make/armlink_adapter.sh"
             STRIP=arm-none-linux-gnueabi-strip
             NM=arm-none-linux-gnueabi-nm
             tune_cflags="--cpu="
@@ -1339,10 +1339,10 @@
     if enabled source_path_used; then
     # Prepare the PWD for building.
     for f in ${OOT_INSTALLS}; do
-            install -D ${source_path}/$f $f
+            install -D "${source_path}/$f" "$f"
     done
     fi
-    cp ${source_path}/build/make/Makefile .
+    cp "${source_path}/build/make/Makefile" .
 
     clean_temp_files
     true
diff --git a/build/make/gen_msvs_proj.sh b/build/make/gen_msvs_proj.sh
index df91435..4e803b8 100755
--- a/build/make/gen_msvs_proj.sh
+++ b/build/make/gen_msvs_proj.sh
@@ -9,11 +9,11 @@
 ##  be found in the AUTHORS file in the root of the source tree.
 ##
 
-
 self=$0
 self_basename=${self##*/}
 self_dirname=$(dirname "$0")
-EOL=$'\n'
+
+. "$self_dirname/msvs_common.sh"|| exit 127
 
 show_help() {
     cat <<EOF
@@ -43,82 +43,6 @@
     exit 1
 }
 
-die() {
-    echo "${self_basename}: $@" >&2
-    exit 1
-}
-
-die_unknown(){
-    echo "Unknown option \"$1\"." >&2
-    echo "See ${self_basename} --help for available options." >&2
-    exit 1
-}
-
-generate_uuid() {
-    local hex="0123456789ABCDEF"
-    local i
-    local uuid=""
-    local j
-    #93995380-89BD-4b04-88EB-625FBE52EBFB
-    for ((i=0; i<32; i++)); do
-        (( j = $RANDOM % 16 ))
-        uuid="${uuid}${hex:$j:1}"
-    done
-    echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
-}
-
-indent1="    "
-indent=""
-indent_push() {
-    indent="${indent}${indent1}"
-}
-indent_pop() {
-    indent="${indent%${indent1}}"
-}
-
-tag_attributes() {
-    for opt in "$@"; do
-        optval="${opt#*=}"
-        [ -n "${optval}" ] ||
-            die "Missing attribute value in '$opt' while generating $tag tag"
-        echo "${indent}${opt%%=*}=\"${optval}\""
-    done
-}
-
-open_tag() {
-    local tag=$1
-    shift
-    if [ $# -ne 0 ]; then
-        echo "${indent}<${tag}"
-        indent_push
-        tag_attributes "$@"
-        echo "${indent}>"
-    else
-        echo "${indent}<${tag}>"
-        indent_push
-    fi
-}
-
-close_tag() {
-    local tag=$1
-    indent_pop
-    echo "${indent}</${tag}>"
-}
-
-tag() {
-    local tag=$1
-    shift
-    if [ $# -ne 0 ]; then
-        echo "${indent}<${tag}"
-        indent_push
-        tag_attributes "$@"
-        indent_pop
-        echo "${indent}/>"
-    else
-        echo "${indent}<${tag}/>"
-    fi
-}
-
 generate_filter() {
     local var=$1
     local name=$2
@@ -143,8 +67,8 @@
             if [ "${f##*.}" == "$pat" ]; then
                 unset file_list[i]
 
-                objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,/,_,g')
-                open_tag File RelativePath="./$f"
+                objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,[:/],_,g')
+                open_tag File RelativePath="$f"
 
                 if [ "$pat" == "asm" ] && $asm_use_custom_step; then
                     for plat in "${platforms[@]}"; do
@@ -211,7 +135,7 @@
         ;;
         --lib) proj_kind="lib"
         ;;
-        --src-path-bare=*) src_path_bare="$optval"
+        --src-path-bare=*) src_path_bare=$(fix_path "$optval")
         ;;
         --static-crt) use_static_runtime=true
         ;;
@@ -226,8 +150,10 @@
         ;;
         -I*)
             opt="${opt%/}"
-            incs="${incs}${incs:+;}&quot;${opt##-I}&quot;"
-            yasmincs="${yasmincs} ${opt}"
+            opt=${opt##-I}
+            opt=$(fix_path "$opt")
+            incs="${incs}${incs:+;}&quot;${opt}&quot;"
+            yasmincs="${yasmincs} -I${opt}"
         ;;
         -D*) defines="${defines}${defines:+;}${opt##-D}"
         ;;
@@ -236,9 +162,11 @@
                 libdirs="${libdirs}${libdirs:+;}&quot;\$(OutDir)&quot;"
             else
                  # Also try directories for this platform/configuration
-                 libdirs="${libdirs}${libdirs:+;}&quot;${opt##-L}&quot;"
-                 libdirs="${libdirs}${libdirs:+;}&quot;${opt##-L}/\$(PlatformName)/\$(ConfigurationName)&quot;"
-                 libdirs="${libdirs}${libdirs:+;}&quot;${opt##-L}/\$(PlatformName)&quot;"
+                 opt=${opt##-L}
+                 opt=$(fix_path "$opt")
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}&quot;"
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)/\$(ConfigurationName)&quot;"
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)&quot;"
             fi
         ;;
         -l*) libs="${libs}${libs:+ }${opt##-l}.lib"
@@ -246,7 +174,7 @@
         -*) die_unknown $opt
         ;;
         *)
-            file_list[${#file_list[@]}]="$opt"
+            file_list[${#file_list[@]}]="$(fix_path $opt)"
             case "$opt" in
                  *.asm) uses_asm=true
                  ;;
diff --git a/build/make/gen_msvs_vcxproj.sh b/build/make/gen_msvs_vcxproj.sh
index 23990a4..9dc7906 100755
--- a/build/make/gen_msvs_vcxproj.sh
+++ b/build/make/gen_msvs_vcxproj.sh
@@ -9,11 +9,11 @@
 ##  be found in the AUTHORS file in the root of the source tree.
 ##
 
-
 self=$0
 self_basename=${self##*/}
 self_dirname=$(dirname "$0")
-EOL=$'\n'
+
+. "$self_dirname/msvs_common.sh"|| exit 127
 
 show_help() {
     cat <<EOF
@@ -44,82 +44,6 @@
     exit 1
 }
 
-die() {
-    echo "${self_basename}: $@" >&2
-    exit 1
-}
-
-die_unknown(){
-    echo "Unknown option \"$1\"." >&2
-    echo "See ${self_basename} --help for available options." >&2
-    exit 1
-}
-
-generate_uuid() {
-    local hex="0123456789ABCDEF"
-    local i
-    local uuid=""
-    local j
-    #93995380-89BD-4b04-88EB-625FBE52EBFB
-    for ((i=0; i<32; i++)); do
-        (( j = $RANDOM % 16 ))
-        uuid="${uuid}${hex:$j:1}"
-    done
-    echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
-}
-
-indent1="    "
-indent=""
-indent_push() {
-    indent="${indent}${indent1}"
-}
-indent_pop() {
-    indent="${indent%${indent1}}"
-}
-
-tag_attributes() {
-    for opt in "$@"; do
-        optval="${opt#*=}"
-        [ -n "${optval}" ] ||
-            die "Missing attribute value in '$opt' while generating $tag tag"
-        echo "${indent}${opt%%=*}=\"${optval}\""
-    done
-}
-
-open_tag() {
-    local tag=$1
-    shift
-    if [ $# -ne 0 ]; then
-        echo "${indent}<${tag}"
-        indent_push
-        tag_attributes "$@"
-        echo "${indent}>"
-    else
-        echo "${indent}<${tag}>"
-        indent_push
-    fi
-}
-
-close_tag() {
-    local tag=$1
-    indent_pop
-    echo "${indent}</${tag}>"
-}
-
-tag() {
-    local tag=$1
-    shift
-    if [ $# -ne 0 ]; then
-        echo "${indent}<${tag}"
-        indent_push
-        tag_attributes "$@"
-        indent_pop
-        echo "${indent}/>"
-    else
-        echo "${indent}<${tag}/>"
-    fi
-}
-
 tag_content() {
     local tag=$1
     local content=$2
@@ -154,7 +78,7 @@
             if [ "${f##*.}" == "$pat" ]; then
                 unset file_list[i]
 
-                objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,/,_,g')
+                objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,[:/],_,g')
 
                 if ([ "$pat" == "asm" ] || [ "$pat" == "s" ]) && $asm_use_custom_step; then
                     # Avoid object file name collisions, i.e. vpx_config.c and
@@ -162,7 +86,7 @@
                     # this additional suffix.
                     objf=${objf%.obj}_asm.obj
                     open_tag CustomBuild \
-                        Include=".\\$f"
+                        Include="$f"
                     for plat in "${platforms[@]}"; do
                         for cfg in Debug Release; do
                             tag_content Message "Assembling %(Filename)%(Extension)" \
@@ -177,7 +101,7 @@
                 elif [ "$pat" == "c" ] || \
                      [ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then
                     open_tag ClCompile \
-                        Include=".\\$f"
+                        Include="$f"
                     # Separate file names with Condition?
                     tag_content ObjectFileName "\$(IntDir)$objf"
                     # Check for AVX and turn it on to avoid warnings.
@@ -187,7 +111,7 @@
                     close_tag ClCompile
                 elif [ "$pat" == "h" ] ; then
                     tag ClInclude \
-                        Include=".\\$f"
+                        Include="$f"
                 elif [ "$pat" == "vcxproj" ] ; then
                     open_tag ProjectReference \
                         Include="$f"
@@ -197,7 +121,7 @@
                     close_tag ProjectReference
                 else
                     tag None \
-                        Include=".\\$f"
+                        Include="$f"
                 fi
 
                 break
@@ -231,7 +155,7 @@
         ;;
         --lib) proj_kind="lib"
         ;;
-        --src-path-bare=*) src_path_bare="$optval"
+        --src-path-bare=*) src_path_bare=$(fix_path "$optval")
         ;;
         --static-crt) use_static_runtime=true
         ;;
@@ -248,19 +172,23 @@
         ;;
         -I*)
             opt="${opt%/}"
-            incs="${incs}${incs:+;}${opt##-I}"
-            yasmincs="${yasmincs} ${opt}"
+            opt=${opt##-I}
+            opt=$(fix_path "$opt")
+            incs="${incs}${incs:+;}&quot;${opt}&quot;"
+            yasmincs="${yasmincs} -I${opt}"
         ;;
         -D*) defines="${defines}${defines:+;}${opt##-D}"
         ;;
         -L*) # fudge . to $(OutDir)
             if [ "${opt##-L}" == "." ]; then
-                libdirs="${libdirs}${libdirs:+;}\$(OutDir)"
+                libdirs="${libdirs}${libdirs:+;}&quot;\$(OutDir)&quot;"
             else
                  # Also try directories for this platform/configuration
-                 libdirs="${libdirs}${libdirs:+;}${opt##-L}"
-                 libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)/\$(Configuration)"
-                 libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)"
+                 opt=${opt##-L}
+                 opt=$(fix_path "$opt")
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}&quot;"
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)/\$(Configuration)&quot;"
+                 libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)&quot;"
             fi
         ;;
         -l*) libs="${libs}${libs:+ }${opt##-l}.lib"
@@ -268,7 +196,7 @@
         -*) die_unknown $opt
         ;;
         *)
-            file_list[${#file_list[@]}]="$opt"
+            file_list[${#file_list[@]}]="$(fix_path $opt)"
             case "$opt" in
                  *.asm|*.s) uses_asm=true
                  ;;
diff --git a/build/make/msvs_common.sh b/build/make/msvs_common.sh
new file mode 100644
index 0000000..eb2eb7b
--- /dev/null
+++ b/build/make/msvs_common.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+
+if [ "$(uname -o 2>/dev/null)" = "Cygwin" ] \
+   && cygpath --help >/dev/null 2>&1; then
+    FIXPATH='cygpath -m'
+else
+    FIXPATH='echo'
+fi
+
+die() {
+    echo "${self_basename}: $@" >&2
+    exit 1
+}
+
+die_unknown(){
+    echo "Unknown option \"$1\"." >&2
+    echo "See ${self_basename} --help for available options." >&2
+    exit 1
+}
+
+fix_path() {
+    $FIXPATH "$1"
+}
+
+generate_uuid() {
+    local hex="0123456789ABCDEF"
+    local i
+    local uuid=""
+    local j
+    #93995380-89BD-4b04-88EB-625FBE52EBFB
+    for ((i=0; i<32; i++)); do
+        (( j = $RANDOM % 16 ))
+        uuid="${uuid}${hex:$j:1}"
+    done
+    echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
+}
+
+indent1="    "
+indent=""
+indent_push() {
+    indent="${indent}${indent1}"
+}
+indent_pop() {
+    indent="${indent%${indent1}}"
+}
+
+tag_attributes() {
+    for opt in "$@"; do
+        optval="${opt#*=}"
+        [ -n "${optval}" ] ||
+            die "Missing attribute value in '$opt' while generating $tag tag"
+        echo "${indent}${opt%%=*}=\"${optval}\""
+    done
+}
+
+open_tag() {
+    local tag=$1
+    shift
+    if [ $# -ne 0 ]; then
+        echo "${indent}<${tag}"
+        indent_push
+        tag_attributes "$@"
+        echo "${indent}>"
+    else
+        echo "${indent}<${tag}>"
+        indent_push
+    fi
+}
+
+close_tag() {
+    local tag=$1
+    indent_pop
+    echo "${indent}</${tag}>"
+}
+
+tag() {
+    local tag=$1
+    shift
+    if [ $# -ne 0 ]; then
+        echo "${indent}<${tag}"
+        indent_push
+        tag_attributes "$@"
+        indent_pop
+        echo "${indent}/>"
+    else
+        echo "${indent}<${tag}/>"
+    fi
+}
+
diff --git a/build/make/version.sh b/build/make/version.sh
index e31e568..b340142 100755
--- a/build/make/version.sh
+++ b/build/make/version.sh
@@ -24,9 +24,9 @@
 id=${3:-VERSION_STRING}
 
 git_version_id=""
-if [ -d ${source_path}/.git ]; then
+if [ -d "${source_path}/.git" ]; then
     # Source Path is a git working copy. Check for local modifications.
-    export GIT_DIR=${source_path}/.git
+    export GIT_DIR="${source_path}/.git"
     git_version_id=`git describe --match=v[0-9]* 2>/dev/null`
 fi
 
diff --git a/configure b/configure
index ff350cc..29683cd 100755
--- a/configure
+++ b/configure
@@ -158,7 +158,7 @@
 
 # all targets available are enabled, by default.
 for t in ${all_targets}; do
-    [ -f ${source_path}/${t}.mk ] && enable_feature ${t}
+    [ -f "${source_path}/${t}.mk" ] && enable_feature ${t}
 done
 
 if ! perl --version >/dev/null; then
@@ -166,9 +166,9 @@
 fi
 
 
-if [ "`cd ${source_path} && pwd`" != "`pwd`" ]; then
+if [ "`cd \"${source_path}\" && pwd`" != "`pwd`" ]; then
   # test to see if source_path already configured
-  if [ -f ${source_path}/vpx_config.h ]; then
+  if [ -f "${source_path}/vpx_config.h" ]; then
     die "source directory already configured; run 'make distclean' there first"
   fi
 fi
@@ -201,27 +201,27 @@
 enable_feature os_support
 enable_feature temporal_denoising
 
-[ -d ${source_path}/../include ] && enable_feature alt_tree_layout
+[ -d "${source_path}/../include" ] && enable_feature alt_tree_layout
 for d in vp8 vp9; do
-    [ -d ${source_path}/${d} ] && disable_feature alt_tree_layout;
+    [ -d "${source_path}/${d}" ] && disable_feature alt_tree_layout;
 done
 
 if ! enabled alt_tree_layout; then
 # development environment
-[ -d ${source_path}/vp8 ] && CODECS="${CODECS} vp8_encoder vp8_decoder"
-[ -d ${source_path}/vp9 ] && CODECS="${CODECS} vp9_encoder vp9_decoder"
+[ -d "${source_path}/vp8" ] && CODECS="${CODECS} vp8_encoder vp8_decoder"
+[ -d "${source_path}/vp9" ] && CODECS="${CODECS} vp9_encoder vp9_decoder"
 else
 # customer environment
-[ -f ${source_path}/../include/vpx/vp8cx.h ] && CODECS="${CODECS} vp8_encoder"
-[ -f ${source_path}/../include/vpx/vp8dx.h ] && CODECS="${CODECS} vp8_decoder"
-[ -f ${source_path}/../include/vpx/vp9cx.h ] && CODECS="${CODECS} vp9_encoder"
-[ -f ${source_path}/../include/vpx/vp9dx.h ] && CODECS="${CODECS} vp9_decoder"
-[ -f ${source_path}/../include/vpx/vp8cx.h ] || disable_feature vp8_encoder
-[ -f ${source_path}/../include/vpx/vp8dx.h ] || disable_feature vp8_decoder
-[ -f ${source_path}/../include/vpx/vp9cx.h ] || disable_feature vp9_encoder
-[ -f ${source_path}/../include/vpx/vp9dx.h ] || disable_feature vp9_decoder
+[ -f "${source_path}/../include/vpx/vp8cx.h" ] && CODECS="${CODECS} vp8_encoder"
+[ -f "${source_path}/../include/vpx/vp8dx.h" ] && CODECS="${CODECS} vp8_decoder"
+[ -f "${source_path}/../include/vpx/vp9cx.h" ] && CODECS="${CODECS} vp9_encoder"
+[ -f "${source_path}/../include/vpx/vp9dx.h" ] && CODECS="${CODECS} vp9_decoder"
+[ -f "${source_path}/../include/vpx/vp8cx.h" ] || disable_feature vp8_encoder
+[ -f "${source_path}/../include/vpx/vp8dx.h" ] || disable_feature vp8_decoder
+[ -f "${source_path}/../include/vpx/vp9cx.h" ] || disable_feature vp9_encoder
+[ -f "${source_path}/../include/vpx/vp9dx.h" ] || disable_feature vp9_decoder
 
-[ -f ${source_path}/../lib/*/*mt.lib ] && soft_enable static_msvcrt
+[ -f "${source_path}/../lib/*/*mt.lib" ] && soft_enable static_msvcrt
 fi
 
 CODECS="$(echo ${CODECS} | tr ' ' '\n')"
@@ -317,7 +317,6 @@
     multi_res_encoding
     temporal_denoising
     experimental
-    decrypt
     ${EXPERIMENT_LIST}
 "
 CMDLINE_SELECT="
@@ -371,7 +370,6 @@
     multi_res_encoding
     temporal_denoising
     experimental
-    decrypt
 "
 
 process_cmdline() {
@@ -468,7 +466,7 @@
           ;;
     esac
     if [ -f "${source_path}/build/make/version.sh" ]; then
-        local ver=`"$source_path/build/make/version.sh" --bare $source_path`
+        local ver=`"$source_path/build/make/version.sh" --bare "$source_path"`
         DIST_DIR="${DIST_DIR}-${ver}"
         VERSION_STRING=${ver}
         ver=${ver%%-*}
@@ -704,13 +702,11 @@
         enabled postproc || die "postproc_visualizer requires postproc to be enabled"
     fi
 
-    # Enable WebM IO by default.
-    soft_enable webm_io
-
     # Enable unit tests by default if we have a working C++ compiler.
     case "$toolchain" in
         *-vs*)
             soft_enable unit_tests
+            soft_enable webm_io
         ;;
         *-android-*)
             # GTestLog must be modified to use Android logging utilities.
@@ -726,13 +722,21 @@
             check_cxx "$@" <<EOF && soft_enable unit_tests
 int z;
 EOF
+            check_cxx "$@" <<EOF && soft_enable webm_io
+int z;
+EOF
         ;;
         *)
             enabled pthread_h && check_cxx "$@" <<EOF && soft_enable unit_tests
 int z;
 EOF
+            check_cxx "$@" <<EOF && soft_enable webm_io
+int z;
+EOF
         ;;
     esac
+    # libwebm needs to be linked with C++ standard library
+    enabled webm_io && LD=${CXX}
 }
 
 
diff --git a/examples.mk b/examples.mk
index fa5d66c..f6e7c00 100644
--- a/examples.mk
+++ b/examples.mk
@@ -15,6 +15,21 @@
                 third_party/libyuv/source/scale.c  \
                 third_party/libyuv/source/cpu_id.c
 
+LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
+                      third_party/libwebm/mkvmuxerutil.cpp \
+                      third_party/libwebm/mkvwriter.cpp \
+                      third_party/libwebm/mkvmuxer.hpp \
+                      third_party/libwebm/mkvmuxertypes.hpp \
+                      third_party/libwebm/mkvmuxerutil.hpp \
+                      third_party/libwebm/mkvparser.hpp \
+                      third_party/libwebm/mkvwriter.hpp \
+                      third_party/libwebm/webmids.hpp
+
+LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser.cpp \
+                      third_party/libwebm/mkvreader.cpp \
+                      third_party/libwebm/mkvparser.hpp \
+                      third_party/libwebm/mkvreader.hpp
+
 # List of examples to build. UTILS are tools meant for distribution
 # while EXAMPLES demonstrate specific portions of the API.
 UTILS-$(CONFIG_DECODERS)    += vpxdec.c
@@ -29,14 +44,8 @@
 vpxdec.SRCS                 += y4menc.c y4menc.h
 vpxdec.SRCS                 += $(LIBYUV_SRCS)
 ifeq ($(CONFIG_WEBM_IO),yes)
-  vpxdec.SRCS                 += third_party/nestegg/halloc/halloc.h
-  vpxdec.SRCS                 += third_party/nestegg/halloc/src/align.h
-  vpxdec.SRCS                 += third_party/nestegg/halloc/src/halloc.c
-  vpxdec.SRCS                 += third_party/nestegg/halloc/src/hlist.h
-  vpxdec.SRCS                 += third_party/nestegg/halloc/src/macros.h
-  vpxdec.SRCS                 += third_party/nestegg/include/nestegg/nestegg.h
-  vpxdec.SRCS                 += third_party/nestegg/src/nestegg.c
-  vpxdec.SRCS                 += webmdec.c webmdec.h
+  vpxdec.SRCS                 += $(LIBWEBM_PARSER_SRCS)
+  vpxdec.SRCS                 += webmdec.cc webmdec.h
 endif
 vpxdec.GUID                  = BA5FE66F-38DD-E034-F542-B1578C5FB950
 vpxdec.DESCRIPTION           = Full featured decoder
@@ -53,10 +62,8 @@
 vpxenc.SRCS                 += vpxstats.c vpxstats.h
 vpxenc.SRCS                 += $(LIBYUV_SRCS)
 ifeq ($(CONFIG_WEBM_IO),yes)
-  vpxenc.SRCS                 += third_party/libmkv/EbmlIDs.h
-  vpxenc.SRCS                 += third_party/libmkv/EbmlWriter.c
-  vpxenc.SRCS                 += third_party/libmkv/EbmlWriter.h
-  vpxenc.SRCS                 += webmenc.c webmenc.h
+  vpxenc.SRCS                 += $(LIBWEBM_MUXER_SRCS)
+  vpxenc.SRCS                 += webmenc.cc webmenc.h
 endif
 vpxenc.GUID                  = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
 vpxenc.DESCRIPTION           = Full featured encoder
diff --git a/examples/vpx_temporal_scalable_patterns.c b/examples/vpx_temporal_scalable_patterns.c
index 5cb4ee9..07dd318 100644
--- a/examples/vpx_temporal_scalable_patterns.c
+++ b/examples/vpx_temporal_scalable_patterns.c
@@ -526,7 +526,7 @@
   // Enable error resilient mode.
   cfg.g_error_resilient = 1;
   cfg.g_lag_in_frames   = 0;
-  cfg.kf_mode = VPX_KF_DISABLED;
+  cfg.kf_mode = VPX_KF_AUTO;
 
   // Disable automatic keyframe placement.
   cfg.kf_min_dist = cfg.kf_max_dist = 3000;
diff --git a/libs.mk b/libs.mk
index a5c4b76..85c5f8a 100644
--- a/libs.mk
+++ b/libs.mk
@@ -531,3 +531,28 @@
 
 ## Update the global src list
 SRCS += $(CODEC_SRCS) $(LIBVPX_TEST_SRCS) $(GTEST_SRCS)
+
+##
+## vpxdec/vpxenc tests.
+##
+ifeq ($(CONFIG_UNIT_TESTS),yes)
+TEST_BIN_PATH = .
+ifeq ($(CONFIG_MSVS),yes)
+# MSVC will build both Debug and Release configurations of tools in a
+# sub directory named for the current target. Assume the user wants to
+# run the Release tools, and assign TEST_BIN_PATH accordingly.
+# TODO(tomfinegan): Is this adequate for ARM?
+# TODO(tomfinegan): Support running the debug versions of tools?
+TEST_BIN_PATH := $(addsuffix /$(TGT_OS:win64=x64)/Release, $(TEST_BIN_PATH))
+endif
+utiltest: testdata
+	$(qexec)$(SRC_PATH_BARE)/test/vpxdec.sh \
+		--test-data-path $(LIBVPX_TEST_DATA_PATH) \
+		--bin-path $(TEST_BIN_PATH)
+	$(qexec)$(SRC_PATH_BARE)/test/vpxenc.sh \
+		--test-data-path $(LIBVPX_TEST_DATA_PATH) \
+		--bin-path $(TEST_BIN_PATH)
+else
+utiltest:
+	@echo Unit tests must be enabled to make the utiltest target.
+endif
diff --git a/test/convolve_test.cc b/test/convolve_test.cc
index e920de8..37ee0ef 100644
--- a/test/convolve_test.cc
+++ b/test/convolve_test.cc
@@ -306,19 +306,13 @@
           << "(" << x << "," << y << ")";
 }
 
-const int16_t (*kTestFilterList[])[8] = {
-  vp9_bilinear_filters,
-  vp9_sub_pel_filters_8,
-  vp9_sub_pel_filters_8s,
-  vp9_sub_pel_filters_8lp
-};
-const int kNumFilterBanks = sizeof(kTestFilterList) /
-                            sizeof(kTestFilterList[0]);
+const int kNumFilterBanks = 4;
 const int kNumFilters = 16;
 
 TEST(ConvolveTest, FiltersWontSaturateWhenAddedPairwise) {
   for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
-    const int16_t (*filters)[8] = kTestFilterList[filter_bank];
+    const InterpKernel *filters =
+        vp9_get_interp_kernel(static_cast<INTERP_FILTER>(filter_bank));
     for (int i = 0; i < kNumFilters; i++) {
       const int p0 = filters[i][0] + filters[i][1];
       const int p1 = filters[i][2] + filters[i][3];
@@ -345,8 +339,8 @@
 
 
   for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
-    const int16_t (*filters)[8] = kTestFilterList[filter_bank];
-
+    const InterpKernel *filters =
+        vp9_get_interp_kernel(static_cast<INTERP_FILTER>(filter_bank));
     for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
       for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
         filter_block2d_8_c(in, kInputStride,
@@ -399,12 +393,9 @@
     }
   }
 
-  const int kNumFilterBanks = sizeof(kTestFilterList) /
-      sizeof(kTestFilterList[0]);
-
   for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
-    const int16_t (*filters)[8] = kTestFilterList[filter_bank];
-    const int kNumFilters = 16;
+    const InterpKernel *filters =
+        vp9_get_interp_kernel(static_cast<INTERP_FILTER>(filter_bank));
 
     for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
       for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index e8604a6..2b4aa3a 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -145,7 +145,7 @@
     cfg_.rc_target_bitrate = i;
     ResetModel();
     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
-    ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_)
+    ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
         << " The datarate for the file exceeds the target!";
 
     ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
diff --git a/test/decode_to_md5.sh b/test/decode_to_md5.sh
new file mode 100755
index 0000000..f64acc8
--- /dev/null
+++ b/test/decode_to_md5.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+##  This file tests the libvpx decode_to_md5 example. To add new tests to this
+##  file, do the following:
+##    1. Write a shell function (this is your test).
+##    2. Add the function to decode_to_md5_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+# Environment check: Make sure input is available:
+#   $VP8_IVF_FILE and $VP9_IVF_FILE are required.
+decode_to_md5_verify_environment() {
+  if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_IVF_FILE}" ]; then
+    echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
+    return 1
+  fi
+}
+
+# Runs decode_to_md5 on $1 and captures the md5 sum for the final frame. $2 is
+# interpreted as codec name and used solely to name the output file. $3 is the
+# expected md5 sum: It must match that of the final frame.
+decode_to_md5() {
+  local decoder="${LIBVPX_BIN_PATH}/decode_to_md5${VPX_TEST_EXE_SUFFIX}"
+  local input_file="$1"
+  local codec="$2"
+  local expected_md5="$3"
+  local output_file="${VPX_TEST_OUTPUT_DIR}/decode_to_md5_${codec}"
+
+  [ -x "${decoder}" ] || return 1
+
+  eval "${decoder}" "${input_file}" "${output_file}" ${devnull}
+
+  [ -e "${output_file}" ] || return 1
+
+  local md5_last_frame=$(tail -n1 "${output_file}")
+  local actual_md5=$(echo "${md5_last_frame% *}" | tr -d [:space:])
+  [ "${actual_md5}" = "${expected_md5}" ] || return 1
+}
+
+decode_to_md5_vp8() {
+  # expected MD5 sum for the last frame.
+  local expected_md5="56794d911b02190212bca92f88ad60c6"
+
+  if [ "$(vp8_decode_available)" = "yes" ]; then
+    decode_to_md5 "${VP8_IVF_FILE}" "vp8" "${expected_md5}"
+  fi
+}
+
+decode_to_md5_vp9() {
+  # expected MD5 sum for the last frame.
+  local expected_md5="2952c0eae93f3dadd1aa84c50d3fd6d2"
+
+  if [ "$(vp9_decode_available)" = "yes" ]; then
+    decode_to_md5 "${VP9_IVF_FILE}" "vp9" "${expected_md5}"
+  fi
+}
+
+decode_to_md5_tests="decode_to_md5_vp8
+                     decode_to_md5_vp9"
+
+run_tests decode_to_md5_verify_environment "${decode_to_md5_tests}"
diff --git a/test/decode_with_drops.sh b/test/decode_with_drops.sh
new file mode 100755
index 0000000..82e934d
--- /dev/null
+++ b/test/decode_with_drops.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+##  This file tests the libvpx decode_with_drops example. To add new tests to
+##  this file, do the following:
+##    1. Write a shell function (this is your test).
+##    2. Add the function to decode_with_drops_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+# Environment check: Make sure input is available:
+#   $VP8_IVF_FILE and $VP9_IVF_FILE are required.
+decode_with_drops_verify_environment() {
+  if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_IVF_FILE}" ]; then
+    echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
+    return 1
+  fi
+}
+
+# Runs decode_with_drops on $1, $2 is interpreted as codec name and used solely
+# to name the output file. $3 is the drop mode, and is passed directly to
+# decode_with_drops.
+decode_with_drops() {
+  local decoder="${LIBVPX_BIN_PATH}/decode_with_drops${VPX_TEST_EXE_SUFFIX}"
+  local input_file="$1"
+  local codec="$2"
+  local output_file="${VPX_TEST_OUTPUT_DIR}/decode_with_drops_${codec}"
+  local drop_mode="$3"
+
+  [ -x "${decoder}" ] || return 1
+
+  eval "${decoder}" "${input_file}" "${output_file}" "${drop_mode}" ${devnull}
+
+  [ -e "${output_file}" ] || return 1
+}
+
+# Decodes $VP8_IVF_FILE while dropping frames, twice: once in sequence mode,
+# and once in pattern mode.
+# Note: This test assumes that $VP8_IVF_FILE has exactly 29 frames, and could
+# break if the file is modified.
+decode_with_drops_vp8() {
+  if [ "$(vp8_decode_available)" = "yes" ]; then
+    # Test sequence mode: Drop frames 2-28.
+    decode_with_drops "${VP8_IVF_FILE}" "vp8" "2-28"
+
+    # Test pattern mode: Drop 3 of every 4 frames.
+    decode_with_drops "${VP8_IVF_FILE}" "vp8" "3/4"
+  fi
+}
+
+# Decodes $VP9_IVF_FILE while dropping frames, twice: once in sequence mode,
+# and once in pattern mode.
+# Note: This test assumes that $VP9_IVF_FILE has exactly 20 frames, and could
+# break if the file is modified.
+decode_with_drops_vp9() {
+  if [ "$(vp9_decode_available)" = "yes" ]; then
+    # Test sequence mode: Drop frames 2-28.
+    decode_with_drops "${VP9_IVF_FILE}" "vp9" "2-19"
+
+    # Test pattern mode: Drop 3 of every 4 frames.
+    decode_with_drops "${VP9_IVF_FILE}" "vp9" "3/4"
+  fi
+}
+
+decode_with_drops_tests="decode_with_drops_vp8
+                         decode_with_drops_vp9"
+
+run_tests decode_with_drops_verify_environment "${decode_with_drops_tests}"
diff --git a/test/examples.sh b/test/examples.sh
new file mode 100755
index 0000000..ac2a18c
--- /dev/null
+++ b/test/examples.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+##  This file runs all of the tests for the libvpx examples.
+##
+. $(dirname $0)/tools_common.sh
+
+example_tests=$(ls $(dirname $0)/*.sh)
+
+# List of script names to exclude.
+exclude_list="examples vpxdec vpxenc tools_common"
+
+# Filter out the scripts in $exclude_list.
+for word in ${exclude_list}; do
+  example_tests=$(filter_strings "${example_tests}" "${word}" exclude)
+done
+
+for test in ${example_tests}; do
+  # Source each test script so that exporting variables can be avoided.
+  . "${test}"
+done
diff --git a/test/external_frame_buffer_test.cc b/test/external_frame_buffer_test.cc
index 54c79e9..fb0449d 100644
--- a/test/external_frame_buffer_test.cc
+++ b/test/external_frame_buffer_test.cc
@@ -10,13 +10,16 @@
 
 #include <string>
 
+#include "./vpx_config.h"
 #include "test/codec_factory.h"
 #include "test/decode_test_driver.h"
 #include "test/ivf_video_source.h"
 #include "test/md5_helper.h"
 #include "test/test_vectors.h"
 #include "test/util.h"
+#if CONFIG_WEBM_IO
 #include "test/webm_video_source.h"
+#endif
 
 namespace {
 
@@ -267,6 +270,7 @@
   ExternalFrameBufferList fb_list_;
 };
 
+#if CONFIG_WEBM_IO
 // Class for testing passing in external frame buffers to libvpx.
 class ExternalFrameBufferTest : public ::testing::Test {
  protected:
@@ -340,6 +344,7 @@
   int num_buffers_;
   ExternalFrameBufferList fb_list_;
 };
+#endif  // CONFIG_WEBM_IO
 
 // This test runs through the set of test vectors, and decodes them.
 // Libvpx will call into the application to allocate a frame buffer when
@@ -366,7 +371,13 @@
   if (filename.substr(filename.length() - 3, 3) == "ivf") {
     video = new libvpx_test::IVFVideoSource(filename);
   } else {
+#if CONFIG_WEBM_IO
     video = new libvpx_test::WebMVideoSource(filename);
+#else
+    fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
+            filename.c_str());
+    return;
+#endif
   }
   ASSERT_TRUE(video != NULL);
   video->Init();
@@ -380,6 +391,7 @@
   delete video;
 }
 
+#if CONFIG_WEBM_IO
 TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
   // Minimum number of external frame buffers for VP9 is
   // #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS.
@@ -460,6 +472,7 @@
             SetFrameBufferFunctions(
                 num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
 }
+#endif  // CONFIG_WEBM_IO
 
 VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
                           ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
diff --git a/test/simple_decoder.sh b/test/simple_decoder.sh
new file mode 100755
index 0000000..24b17c5
--- /dev/null
+++ b/test/simple_decoder.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+##  This file tests the libvpx simple_decoder example code. To add new tests to
+##  this file, do the following:
+##    1. Write a shell function (this is your test).
+##    2. Add the function to simple_decoder_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+# Environment check: Make sure input is available:
+#   $VP8_IVF_FILE and $VP9_IVF_FILE are required.
+simple_decoder_verify_environment() {
+  if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_IVF_FILE}" ]; then
+    echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
+    return 1
+  fi
+}
+
+# Runs simple_decoder using $1 as input file. $2 is the codec name, and is used
+# solely to name the output file.
+simple_decoder() {
+  local decoder="${LIBVPX_BIN_PATH}/simple_decoder${VPX_TEST_EXE_SUFFIX}"
+  local input_file="$1"
+  local codec="$2"
+  local output_file="${VPX_TEST_OUTPUT_DIR}/simple_decoder_${codec}.raw"
+
+  [ -x "${decoder}" ] || return 1
+
+  eval "${decoder}" "${input_file}" "${output_file}" ${devnull}
+
+  [ -e "${output_file}" ] || return 1
+}
+
+simple_decoder_vp8() {
+  if [ "$(vp8_decode_available)" = "yes" ]; then
+    simple_decoder "${VP8_IVF_FILE}" vp8 || return 1
+  fi
+}
+
+simple_decoder_vp9() {
+  if [ "$(vp9_decode_available)" = "yes" ]; then
+    simple_decoder "${VP9_IVF_FILE}" vp9 || return 1
+  fi
+}
+
+simple_decoder_tests="simple_decoder_vp8
+                      simple_decoder_vp9"
+
+run_tests simple_decoder_verify_environment "${simple_decoder_tests}"
diff --git a/test/simple_encoder.sh b/test/simple_encoder.sh
new file mode 100755
index 0000000..6232093
--- /dev/null
+++ b/test/simple_encoder.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+##
+##  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+##
+##  Use of this source code is governed by a BSD-style license
+##  that can be found in the LICENSE file in the root of the source
+##  tree. An additional intellectual property rights grant can be found
+##  in the file PATENTS.  All contributing project authors may
+##  be found in the AUTHORS file in the root of the source tree.
+##
+##  This file tests the libvpx simple_encoder example. To add new tests to this
+##  file, do the following:
+##    1. Write a shell function (this is your test).
+##    2. Add the function to simple_encoder_tests (on a new line).
+##
+. $(dirname $0)/tools_common.sh
+
+# Environment check: $YUV_RAW_INPUT is required.
+simple_encoder_verify_environment() {
+  if [ ! -e "${YUV_RAW_INPUT}" ]; then
+    echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
+    return 1
+  fi
+}
+
+# Runs simple_encoder using the codec specified by $1.
+simple_encoder() {
+  local encoder="${LIBVPX_BIN_PATH}/simple_encoder${VPX_TEST_EXE_SUFFIX}"
+  local codec="$1"
+  local output_file="${VPX_TEST_OUTPUT_DIR}/simple_encoder_${codec}.ivf"
+
+  [ -x "${encoder}" ] || return 1
+
+  eval "${encoder}" "${codec}" "${YUV_RAW_INPUT_WIDTH}" \
+      "${YUV_RAW_INPUT_HEIGHT}" "${YUV_RAW_INPUT}" "${output_file}" 9999 \
+      ${devnull}
+
+  [ -e "${output_file}" ] || return 1
+}
+
+simple_encoder_vp8() {
+  if [ "$(vp8_encode_available)" = "yes" ]; then
+    simple_encoder vp8 || return 1
+  fi
+}
+
+# TODO(tomfinegan): Add a frame limit param to simple_encoder and enable this
+# test. VP9 is just too slow right now: This test takes 4m30s+ on a fast
+# machine.
+DISABLED_simple_encoder_vp9() {
+  if [ "$(vp9_encode_available)" = "yes" ]; then
+    simple_encoder vp9 || return 1
+  fi
+}
+
+simple_encoder_tests="simple_encoder_vp8
+                      DISABLED_simple_encoder_vp9"
+
+run_tests simple_encoder_verify_environment "${simple_encoder_tests}"
diff --git a/test/test.mk b/test/test.mk
index 92664e2..0dcb6c8 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -42,19 +42,24 @@
 LIBVPX_TEST_SRCS-yes                   += encode_test_driver.h
 
 ## WebM Parsing
-NESTEGG_SRCS                           += ../third_party/nestegg/halloc/halloc.h
-NESTEGG_SRCS                           += ../third_party/nestegg/halloc/src/align.h
-NESTEGG_SRCS                           += ../third_party/nestegg/halloc/src/halloc.c
-NESTEGG_SRCS                           += ../third_party/nestegg/halloc/src/hlist.h
-NESTEGG_SRCS                           += ../third_party/nestegg/include/nestegg/nestegg.h
-NESTEGG_SRCS                           += ../third_party/nestegg/src/nestegg.c
-LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += $(NESTEGG_SRCS)
+ifeq ($(CONFIG_WEBM_IO), yes)
+LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvparser.cpp
+LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvreader.cpp
+LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvparser.hpp
+LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvreader.hpp
+LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += $(LIBWEBM_PARSER_SRCS)
+LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += ../tools_common.h
+LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += ../webmdec.cc
+LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += ../webmdec.h
 LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += webm_video_source.h
+endif
 
 LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += test_vector_test.cc
 
-# Currently we only support decoder perf tests for vp9
-ifeq ($(CONFIG_DECODE_PERF_TESTS)$(CONFIG_VP9_DECODER), yesyes)
+# Currently we only support decoder perf tests for vp9. Also they read from WebM
+# files, so WebM IO is required.
+ifeq ($(CONFIG_DECODE_PERF_TESTS)$(CONFIG_VP9_DECODER)$(CONFIG_WEBM_IO), \
+      yesyesyes)
 LIBVPX_TEST_SRCS-yes                   += decode_perf_test.cc
 endif
 
@@ -103,6 +108,7 @@
 
 LIBVPX_TEST_SRCS-$(CONFIG_VP9)         += convolve_test.cc
 LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += vp9_thread_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += vp9_decrypt_test.cc
 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct16x16_test.cc
 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct32x32_test.cc
 LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += fdct4x4_test.cc
diff --git a/test/test_vector_test.cc b/test/test_vector_test.cc
index 9ba18da..1f294f2 100644
--- a/test/test_vector_test.cc
+++ b/test/test_vector_test.cc
@@ -12,13 +12,16 @@
 #include <cstdlib>
 #include <string>
 #include "third_party/googletest/src/include/gtest/gtest.h"
+#include "./vpx_config.h"
 #include "test/codec_factory.h"
 #include "test/decode_test_driver.h"
 #include "test/ivf_video_source.h"
 #include "test/md5_helper.h"
 #include "test/test_vectors.h"
 #include "test/util.h"
+#if CONFIG_WEBM_IO
 #include "test/webm_video_source.h"
+#endif
 #include "vpx_mem/vpx_mem.h"
 
 namespace {
@@ -75,7 +78,13 @@
   if (filename.substr(filename.length() - 3, 3) == "ivf") {
     video = new libvpx_test::IVFVideoSource(filename);
   } else if (filename.substr(filename.length() - 4, 4) == "webm") {
+#if CONFIG_WEBM_IO
     video = new libvpx_test::WebMVideoSource(filename);
+#else
+    fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
+            filename.c_str());
+    return;
+#endif
   }
   video->Init();
 
diff --git a/test/tools_common.sh b/test/tools_common.sh
index cd79771..30f0fae 100755
--- a/test/tools_common.sh
+++ b/test/tools_common.sh
@@ -9,7 +9,17 @@
 ##  be found in the AUTHORS file in the root of the source tree.
 ##
 ##  This file contains shell code shared by test scripts for libvpx tools.
+
+# Use $VPX_TEST_TOOLS_COMMON_SH as a pseudo include guard.
+if [ -z "${VPX_TEST_TOOLS_COMMON_SH}" ]; then
+VPX_TEST_TOOLS_COMMON_SH=included
+
 set -e
+devnull='> /dev/null 2>&1'
+
+vlog() {
+  [ "${VPX_TEST_VERBOSE_OUTPUT}" = "yes" ] && echo "$@"
+}
 
 # Sets $VPX_TOOL_TEST to the name specified by positional parameter one.
 test_begin() {
@@ -130,11 +140,9 @@
 # Echoes yes to stdout when the file named by positional parameter one exists
 # in LIBVPX_BIN_PATH, and is executable.
 vpx_tool_available() {
-  tool_name="${1}"
-  if [ "$(is_windows_target)" = "yes" ]; then
-    tool_name="${tool_name}.exe"
-  fi
-  [ -x "${LIBVPX_BIN_PATH}/${1}" ] && echo yes
+  local tool_name="$1"
+  local tool="${LIBVPX_BIN_PATH}/${tool_name}${VPX_TEST_EXE_SUFFIX}"
+  [ -x "${tool}" ] && echo yes
 }
 
 # Echoes yes to stdout when vpx_config_option_enabled() reports yes for
@@ -178,8 +186,8 @@
 # present, is interpreted as a boolean flag that means the input should be sent
 # to vpxdec via pipe from cat instead of directly.
 vpxdec() {
-  input="${1}"
-  pipe_input=${2}
+  local input="${1}"
+  local pipe_input=${2}
 
   if [ $# -gt 2 ]; then
     # shift away $1 and $2 so the remaining arguments can be passed to vpxdec
@@ -187,16 +195,12 @@
     shift 2
   fi
 
-  decoder="${LIBVPX_BIN_PATH}/vpxdec"
-
-  if [ "$(is_windows_target)" = "yes" ]; then
-    decoder="${decoder}.exe"
-  fi
+  local decoder="${LIBVPX_BIN_PATH}/vpxdec${VPX_TEST_EXE_SUFFIX}"
 
   if [ -z "${pipe_input}" ]; then
-    "${decoder}" "$input" --summary --noblit "$@" > /dev/null 2>&1
+    eval "${decoder}" "$input" --summary --noblit "$@" ${devnull}
   else
-    cat "${input}" | "${decoder}" - --summary --noblit "$@" > /dev/null 2>&1
+    cat "${input}" | eval "${decoder}" - --summary --noblit "$@" ${devnull}
   fi
 }
 
@@ -218,18 +222,14 @@
 #       Note: Extra flags currently supports a special case: when set to "-"
 #             input is piped to vpxenc via cat.
 vpxenc() {
-  encoder="${LIBVPX_BIN_PATH}/vpxenc"
-  codec="${1}"
-  width=${2}
-  height=${3}
-  frames=${4}
-  input=${5}
-  output="${VPX_TEST_OUTPUT_DIR}/${6}"
-  extra_flags=${7}
-
-  if [ "$(is_windows_target)" = "yes" ]; then
-    encoder="${encoder}.exe"
-  fi
+  local encoder="${LIBVPX_BIN_PATH}/vpxenc${VPX_TEST_EXE_SUFFIX}"
+  local codec="${1}"
+  local width=${2}
+  local height=${3}
+  local frames=${4}
+  local input=${5}
+  local output="${VPX_TEST_OUTPUT_DIR}/${6}"
+  local extra_flags=${7}
 
   # Because --ivf must be within the command line to get IVF from vpxenc.
   if echo "${output}" | egrep -q 'ivf$'; then
@@ -246,14 +246,16 @@
   fi
 
   if [ -z "${pipe_input}" ]; then
-    "${encoder}" --codec=${codec} --width=${width} --height=${height} \
+    eval "${encoder}" --codec=${codec} --width=${width} --height=${height} \
         --limit=${frames} ${use_ivf} ${extra_flags} --output="${output}" \
-        "${input}" > /dev/null 2>&1
+        "${input}" \
+        ${devnull}
   else
     cat "${input}" \
-        | "${encoder}" --codec=${codec} --width=${width} --height=${height} \
-            --limit=${frames} ${use_ivf} ${extra_flags} --output="${output}" - \
-            > /dev/null 2>&1
+        | eval "${encoder}" --codec=${codec} --width=${width} \
+              --height=${height} --limit=${frames} ${use_ivf} ${extra_flags} \
+              --output="${output}" - \
+              ${devnull}
   fi
 
   if [ ! -e "${output}" ]; then
@@ -318,8 +320,9 @@
   # Run tests.
   for test in ${tests_to_run}; do
     test_begin "${test}"
+    vlog "  RUN  ${test}"
     "${test}"
-    [ "${VPX_TEST_VERBOSE_OUTPUT}" = "yes" ] && echo "  PASS ${test}"
+    vlog "  PASS ${test}"
     test_end "${test}"
   done
 
@@ -336,6 +339,7 @@
     --run-disabled-tests: Run disabled tests.
     --help: Display this message and exit.
     --test-data-path <path to libvpx test data directory>
+    --show-program-output: Shows output from all programs being tested.
     --verbose: Verbose output.
 
     When the --bin-path option is not specified the script attempts to use
@@ -388,6 +392,9 @@
     --verbose)
       VPX_TEST_VERBOSE_OUTPUT=yes
       ;;
+    --show-program-output)
+      devnull=
+      ;;
     *)
       vpx_test_usage
       exit 1
@@ -421,11 +428,24 @@
   exit 1
 fi
 
+if [ "$(is_windows_target)" = "yes" ]; then
+  VPX_TEST_EXE_SUFFIX=".exe"
+fi
+
+# Variables shared by tests.
+VP8_IVF_FILE="${LIBVPX_TEST_DATA_PATH}/vp80-00-comprehensive-001.ivf"
+VP9_IVF_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-09-subpixel-00.ivf"
+
+VP9_WEBM_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-00-quantizer-00.webm"
+
+YUV_RAW_INPUT="${LIBVPX_TEST_DATA_PATH}/hantro_collage_w352h288.yuv"
+YUV_RAW_INPUT_WIDTH=352
+YUV_RAW_INPUT_HEIGHT=288
+
+# Setup a trap function to clean up after tests complete.
 trap cleanup EXIT
 
-if [ "${VPX_TEST_VERBOSE_OUTPUT}" = "yes" ]; then
-cat << EOF
-$(basename "${0%.*}") test configuration:
+vlog "$(basename "${0%.*}") test configuration:
   LIBVPX_BIN_PATH=${LIBVPX_BIN_PATH}
   LIBVPX_CONFIG_PATH=${LIBVPX_CONFIG_PATH}
   LIBVPX_TEST_DATA_PATH=${LIBVPX_TEST_DATA_PATH}
@@ -433,5 +453,6 @@
   VPX_TEST_VERBOSE_OUTPUT=${VPX_TEST_VERBOSE_OUTPUT}
   VPX_TEST_FILTER=${VPX_TEST_FILTER}
   VPX_TEST_RUN_DISABLED_TESTS=${VPX_TEST_RUN_DISABLED_TESTS}
-EOF
-fi
+  VPX_TEST_SHOW_PROGRAM_OUTPUT=${VPX_TEST_SHOW_PROGRAM_OUTPUT}"
+
+fi  # End $VPX_TEST_TOOLS_COMMON_SH pseudo include guard.
diff --git a/test/vp8_boolcoder_test.cc b/test/vp8_boolcoder_test.cc
index 9cd1987..99b5f0c 100644
--- a/test/vp8_boolcoder_test.cc
+++ b/test/vp8_boolcoder_test.cc
@@ -94,14 +94,10 @@
         vp8_stop_encode(&bw);
 
         BOOL_DECODER br;
-#if CONFIG_DECRYPT
-        encrypt_buffer(bw_buffer, buffer_size);
-        vp8dx_start_decode(&br, bw_buffer, buffer_size,
+        encrypt_buffer(bw_buffer, kBufferSize);
+        vp8dx_start_decode(&br, bw_buffer, kBufferSize,
                            test_decrypt_cb,
                            reinterpret_cast<void *>(bw_buffer));
-#else
-        vp8dx_start_decode(&br, bw_buffer, kBufferSize, NULL, NULL);
-#endif
         bit_rnd.Reset(random_seed);
         for (int i = 0; i < kBitsToTest; ++i) {
           if (bit_method == 2) {
diff --git a/test/vp8_decrypt_test.cc b/test/vp8_decrypt_test.cc
index 1b5b083..470fdf1 100644
--- a/test/vp8_decrypt_test.cc
+++ b/test/vp8_decrypt_test.cc
@@ -43,7 +43,7 @@
 
 namespace libvpx_test {
 
-TEST(TestDecrypt, DecryptWorks) {
+TEST(TestDecrypt, DecryptWorksVp8) {
   libvpx_test::IVFVideoSource video("vp80-00-comprehensive-001.ivf");
   video.Init();
 
@@ -59,14 +59,12 @@
   // decrypt frame
   video.Next();
 
-#if CONFIG_DECRYPT
   std::vector<uint8_t> encrypted(video.frame_size());
   encrypt_buffer(video.cxdata(), &encrypted[0], video.frame_size(), 0);
-  vp8_decrypt_init di = { test_decrypt_cb, &encrypted[0] };
-  decoder.Control(VP8D_SET_DECRYPTOR, &di);
-#endif  // CONFIG_DECRYPT
+  vpx_decrypt_init di = { test_decrypt_cb, &encrypted[0] };
+  decoder.Control(VPXD_SET_DECRYPTOR, &di);
 
-  res = decoder.DecodeFrame(video.cxdata(), video.frame_size());
+  res = decoder.DecodeFrame(&encrypted[0], encrypted.size());
   ASSERT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
 }
 
diff --git a/test/vp9_boolcoder_test.cc b/test/vp9_boolcoder_test.cc
index c579ade..c7f0cd8 100644
--- a/test/vp9_boolcoder_test.cc
+++ b/test/vp9_boolcoder_test.cc
@@ -70,7 +70,7 @@
         GTEST_ASSERT_EQ(bw_buffer[0] & 0x80, 0);
 
         vp9_reader br;
-        vp9_reader_init(&br, bw_buffer, kBufferSize);
+        vp9_reader_init(&br, bw_buffer, kBufferSize, NULL, NULL);
         bit_rnd.Reset(random_seed);
         for (int i = 0; i < kBitsToTest; ++i) {
           if (bit_method == 2) {
diff --git a/test/vp9_decrypt_test.cc b/test/vp9_decrypt_test.cc
new file mode 100644
index 0000000..88a3c14
--- /dev/null
+++ b/test/vp9_decrypt_test.cc
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "test/codec_factory.h"
+#include "test/ivf_video_source.h"
+
+namespace {
+// In a real use the 'decrypt_state' parameter will be a pointer to a struct
+// with whatever internal state the decryptor uses. For testing we'll just
+// xor with a constant key, and decrypt_state will point to the start of
+// the original buffer.
+const uint8_t test_key[16] = {
+  0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+  0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0
+};
+
+void encrypt_buffer(const uint8_t *src, uint8_t *dst, size_t size,
+                    ptrdiff_t offset) {
+  for (size_t i = 0; i < size; ++i) {
+    dst[i] = src[i] ^ test_key[(offset + i) & 15];
+  }
+}
+
+void test_decrypt_cb(void *decrypt_state, const uint8_t *input,
+                     uint8_t *output, int count) {
+  encrypt_buffer(input, output, count,
+                 input - reinterpret_cast<uint8_t *>(decrypt_state));
+}
+
+}  // namespace
+
+namespace libvpx_test {
+
+TEST(TestDecrypt, DecryptWorksVp9) {
+  libvpx_test::IVFVideoSource video("vp90-2-05-resize.ivf");
+  video.Init();
+
+  vpx_codec_dec_cfg_t dec_cfg = {0};
+  VP9Decoder decoder(dec_cfg, 0);
+
+  video.Begin();
+
+  // no decryption
+  vpx_codec_err_t res = decoder.DecodeFrame(video.cxdata(), video.frame_size());
+  ASSERT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
+
+  // decrypt frame
+  video.Next();
+
+  std::vector<uint8_t> encrypted(video.frame_size());
+  encrypt_buffer(video.cxdata(), &encrypted[0], video.frame_size(), 0);
+  vpx_decrypt_init di = { test_decrypt_cb, &encrypted[0] };
+  decoder.Control(VPXD_SET_DECRYPTOR, &di);
+
+  res = decoder.DecodeFrame(&encrypted[0], encrypted.size());
+  ASSERT_EQ(VPX_CODEC_OK, res) << decoder.DecodeError();
+}
+
+}  // namespace libvpx_test
diff --git a/test/vp9_thread_test.cc b/test/vp9_thread_test.cc
index 5523f20..0c9f71b 100644
--- a/test/vp9_thread_test.cc
+++ b/test/vp9_thread_test.cc
@@ -11,10 +11,13 @@
 #include <string>
 
 #include "third_party/googletest/src/include/gtest/gtest.h"
+#include "./vpx_config.h"
 #include "test/codec_factory.h"
 #include "test/decode_test_driver.h"
 #include "test/md5_helper.h"
+#if CONFIG_WEBM_IO
 #include "test/webm_video_source.h"
+#endif
 #include "vp9/decoder/vp9_thread.h"
 
 namespace {
@@ -97,6 +100,7 @@
 // -----------------------------------------------------------------------------
 // Multi-threaded decode tests
 
+#if CONFIG_WEBM_IO
 // Decodes |filename| with |num_threads|. Returns the md5 of the decoded frames.
 string DecodeFile(const string& filename, int num_threads) {
   libvpx_test::WebMVideoSource video(filename);
@@ -212,6 +216,7 @@
     }
   }
 }
+#endif  // CONFIG_WEBM_IO
 
 INSTANTIATE_TEST_CASE_P(Synchronous, VP9WorkerThreadTest, ::testing::Bool());
 
diff --git a/test/vpxdec.sh b/test/vpxdec.sh
index d236f97..093230b 100755
--- a/test/vpxdec.sh
+++ b/test/vpxdec.sh
@@ -14,9 +14,6 @@
 ##
 . $(dirname $0)/tools_common.sh
 
-VP8_IVF_FILE="${LIBVPX_TEST_DATA_PATH}/vp80-00-comprehensive-001.ivf"
-VP9_WEBM_FILE="${LIBVPX_TEST_DATA_PATH}/vp90-2-00-quantizer-00.webm"
-
 # Environment check: Make sure input is available.
 vpxdec_verify_environment() {
   if [ ! -e "${VP8_IVF_FILE}" ] || [ ! -e "${VP9_WEBM_FILE}" ]; then
diff --git a/test/vpxenc.sh b/test/vpxenc.sh
index 89e4eb3..f08c048 100755
--- a/test/vpxenc.sh
+++ b/test/vpxenc.sh
@@ -15,9 +15,6 @@
 ##
 . $(dirname $0)/tools_common.sh
 
-YUV_RAW_INPUT="${LIBVPX_TEST_DATA_PATH}/hantro_collage_w352h288.yuv"
-YUV_RAW_INPUT_WIDTH=352
-YUV_RAW_INPUT_HEIGHT=288
 TEST_FRAMES=10
 
 # Environment check: Make sure input is available.
diff --git a/test/webm_video_source.h b/test/webm_video_source.h
index 9d88ae3..11d3d23 100644
--- a/test/webm_video_source.h
+++ b/test/webm_video_source.h
@@ -14,73 +14,20 @@
 #include <cstdlib>
 #include <new>
 #include <string>
-#include "third_party/nestegg/include/nestegg/nestegg.h"
+#include "../tools_common.h"
+#include "../webmdec.h"
 #include "test/video_source.h"
 
 namespace libvpx_test {
 
-static int
-nestegg_read_cb(void *buffer, size_t length, void *userdata) {
-  FILE *f = reinterpret_cast<FILE *>(userdata);
-
-  if (fread(buffer, 1, length, f) < length) {
-    if (ferror(f))
-      return -1;
-    if (feof(f))
-      return 0;
-  }
-  return 1;
-}
-
-
-static int
-nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
-  FILE *f = reinterpret_cast<FILE *>(userdata);
-  switch (whence) {
-    case NESTEGG_SEEK_SET:
-      whence = SEEK_SET;
-      break;
-    case NESTEGG_SEEK_CUR:
-      whence = SEEK_CUR;
-      break;
-    case NESTEGG_SEEK_END:
-      whence = SEEK_END;
-      break;
-  };
-  return fseek(f, (long)offset, whence) ? -1 : 0;
-}
-
-
-static int64_t
-nestegg_tell_cb(void *userdata) {
-  FILE *f = reinterpret_cast<FILE *>(userdata);
-  return ftell(f);
-}
-
-
-static void
-nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
-               ...) {
-  va_list ap;
-
-  va_start(ap, format);
-  vfprintf(stderr, format, ap);
-  fprintf(stderr, "\n");
-  va_end(ap);
-}
-
 // This class extends VideoSource to allow parsing of WebM files,
 // so that we can do actual file decodes.
 class WebMVideoSource : public CompressedVideoSource {
  public:
   explicit WebMVideoSource(const std::string &file_name)
       : file_name_(file_name),
-        input_file_(NULL),
-        nestegg_ctx_(NULL),
-        pkt_(NULL),
-        video_track_(0),
-        chunk_(0),
-        chunks_(0),
+        vpx_ctx_(new VpxInputContext()),
+        webm_ctx_(new WebmInputContext()),
         buf_(NULL),
         buf_sz_(0),
         frame_(0),
@@ -88,42 +35,22 @@
   }
 
   virtual ~WebMVideoSource() {
-    if (input_file_)
-      fclose(input_file_);
-    if (nestegg_ctx_ != NULL) {
-      if (pkt_ != NULL) {
-        nestegg_free_packet(pkt_);
-      }
-      nestegg_destroy(nestegg_ctx_);
-    }
+    if (vpx_ctx_->file != NULL)
+      fclose(vpx_ctx_->file);
+    webm_free(webm_ctx_);
+    delete vpx_ctx_;
+    delete webm_ctx_;
   }
 
   virtual void Init() {
   }
 
   virtual void Begin() {
-    input_file_ = OpenTestDataFile(file_name_);
-    ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
+    vpx_ctx_->file = OpenTestDataFile(file_name_);
+    ASSERT_TRUE(vpx_ctx_->file != NULL) << "Input file open failed. Filename: "
         << file_name_;
 
-    nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
-                     input_file_};
-    ASSERT_FALSE(nestegg_init(&nestegg_ctx_, io, NULL, -1))
-        << "nestegg_init failed";
-
-    unsigned int n;
-    ASSERT_FALSE(nestegg_track_count(nestegg_ctx_, &n))
-        << "failed to get track count";
-
-    for (unsigned int i = 0; i < n; i++) {
-      int track_type = nestegg_track_type(nestegg_ctx_, i);
-      ASSERT_GE(track_type, 0) << "failed to get track type";
-
-      if (track_type == NESTEGG_TRACK_VIDEO) {
-        video_track_ = i;
-        break;
-      }
-    }
+    ASSERT_EQ(file_is_webm(webm_ctx_, vpx_ctx_), 1) << "file is not WebM";
 
     FillFrame();
   }
@@ -134,36 +61,12 @@
   }
 
   void FillFrame() {
-    ASSERT_TRUE(input_file_ != NULL);
-    if (chunk_ >= chunks_) {
-      unsigned int track;
-
-      do {
-        /* End of this packet, get another. */
-        if (pkt_ != NULL) {
-          nestegg_free_packet(pkt_);
-          pkt_ = NULL;
-        }
-
-        int again = nestegg_read_packet(nestegg_ctx_, &pkt_);
-        ASSERT_GE(again, 0) << "nestegg_read_packet failed";
-        if (!again) {
-          end_of_file_ = true;
-          return;
-        }
-
-        ASSERT_FALSE(nestegg_packet_track(pkt_, &track))
-            << "nestegg_packet_track failed";
-      } while (track != video_track_);
-
-      ASSERT_FALSE(nestegg_packet_count(pkt_, &chunks_))
-          << "nestegg_packet_count failed";
-      chunk_ = 0;
+    ASSERT_TRUE(vpx_ctx_->file != NULL);
+    const int status = webm_read_frame(webm_ctx_, &buf_, &buf_sz_, &buf_sz_);
+    ASSERT_GE(status, 0) << "webm_read_frame failed";
+    if (status == 1) {
+      end_of_file_ = true;
     }
-
-    ASSERT_FALSE(nestegg_packet_data(pkt_, chunk_, &buf_, &buf_sz_))
-        << "nestegg_packet_data failed";
-    chunk_++;
   }
 
   virtual const uint8_t *cxdata() const {
@@ -174,12 +77,8 @@
 
  protected:
   std::string file_name_;
-  FILE *input_file_;
-  nestegg *nestegg_ctx_;
-  nestegg_packet *pkt_;
-  unsigned int video_track_;
-  unsigned int chunk_;
-  unsigned int chunks_;
+  VpxInputContext *vpx_ctx_;
+  WebmInputContext *webm_ctx_;
   uint8_t *buf_;
   size_t buf_sz_;
   unsigned int frame_;
diff --git a/third_party/googletest/README.webm b/third_party/googletest/README.libvpx
similarity index 100%
rename from third_party/googletest/README.webm
rename to third_party/googletest/README.libvpx
diff --git a/third_party/libwebm/README.webm b/third_party/libwebm/README.libvpx
similarity index 100%
rename from third_party/libwebm/README.webm
rename to third_party/libwebm/README.libvpx
diff --git a/third_party/libyuv/README.webm b/third_party/libyuv/README.libvpx
similarity index 100%
rename from third_party/libyuv/README.webm
rename to third_party/libyuv/README.libvpx
diff --git a/third_party/libyuv/include/libyuv/scale.h b/third_party/libyuv/include/libyuv/scale.h
index 21fe360..35d0ff5 100644
--- a/third_party/libyuv/include/libyuv/scale.h
+++ b/third_party/libyuv/include/libyuv/scale.h
@@ -23,7 +23,7 @@
   kFilterNone = 0,  // Point sample; Fastest
   kFilterBilinear = 1,  // Faster than box, but lower quality scaling down.
   kFilterBox = 2  // Highest quality
-}FilterMode;
+} FilterModeEnum;
 
 // Scales a YUV 4:2:0 image from the src width and height to the
 // dst width and height.
@@ -43,7 +43,7 @@
               uint8* dst_u, int dst_stride_u,
               uint8* dst_v, int dst_stride_v,
               int dst_width, int dst_height,
-              FilterMode filtering);
+              FilterModeEnum filtering);
 
 // Legacy API.  Deprecated
 int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
diff --git a/third_party/libyuv/source/scale.c b/third_party/libyuv/source/scale.c
index 3c30b55..1809300 100644
--- a/third_party/libyuv/source/scale.c
+++ b/third_party/libyuv/source/scale.c
@@ -3053,7 +3053,7 @@
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                             const uint8* src_ptr, uint8* dst_ptr,
-                            FilterMode filtering) {
+                            FilterModeEnum filtering) {
   void (*ScaleRowDown2)(const uint8* src_ptr, int src_stride,
                         uint8* dst_ptr, int dst_width);
   assert(IS_ALIGNED(src_width, 2));
@@ -3097,7 +3097,7 @@
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                             const uint8* src_ptr, uint8* dst_ptr,
-                            FilterMode filtering) {
+                            FilterModeEnum filtering) {
   void (*ScaleRowDown4)(const uint8* src_ptr, int src_stride,
                         uint8* dst_ptr, int dst_width);
   assert(IS_ALIGNED(src_width, 4));
@@ -3142,7 +3142,7 @@
                             int dst_width, int dst_height,
                             int src_stride, int dst_stride,
                             const uint8* src_ptr, uint8* dst_ptr,
-                            FilterMode filtering) {
+                            FilterModeEnum filtering) {
   void (*ScaleRowDown8)(const uint8* src_ptr, int src_stride,
                         uint8* dst_ptr, int dst_width);
   assert(IS_ALIGNED(src_width, 8));
@@ -3181,7 +3181,7 @@
                              int dst_width, int dst_height,
                              int src_stride, int dst_stride,
                              const uint8* src_ptr, uint8* dst_ptr,
-                             FilterMode filtering) {
+                             FilterModeEnum filtering) {
   void (*ScaleRowDown34_0)(const uint8* src_ptr, int src_stride,
                            uint8* dst_ptr, int dst_width);
   void (*ScaleRowDown34_1)(const uint8* src_ptr, int src_stride,
@@ -3274,7 +3274,7 @@
                              int dst_width, int dst_height,
                              int src_stride, int dst_stride,
                              const uint8* src_ptr, uint8* dst_ptr,
-                             FilterMode filtering) {
+                             FilterModeEnum filtering) {
   void (*ScaleRowDown38_3)(const uint8* src_ptr, int src_stride,
                            uint8* dst_ptr, int dst_width);
   void (*ScaleRowDown38_2)(const uint8* src_ptr, int src_stride,
@@ -3634,7 +3634,7 @@
                               int dst_width, int dst_height,
                               int src_stride, int dst_stride,
                               const uint8* src_ptr, uint8* dst_ptr,
-                              FilterMode filtering) {
+                              FilterModeEnum filtering) {
   if (!filtering) {
     ScalePlaneSimple(src_width, src_height, dst_width, dst_height,
                      src_stride, dst_stride, src_ptr, dst_ptr);
@@ -3657,7 +3657,7 @@
                            int dst_width, int dst_height,
                            int src_stride, int dst_stride,
                            const uint8* src_ptr, uint8* dst_ptr,
-                           FilterMode filtering) {
+                           FilterModeEnum filtering) {
   if (!filtering) {
     ScalePlaneSimple(src_width, src_height, dst_width, dst_height,
                      src_stride, dst_stride, src_ptr, dst_ptr);
@@ -3703,7 +3703,7 @@
                        int src_width, int src_height,
                        uint8* dst, int dst_stride,
                        int dst_width, int dst_height,
-                       FilterMode filtering, int use_ref) {
+                       FilterModeEnum filtering, int use_ref) {
   // Use specialized scales to improve performance for common resolutions.
   // For example, all the 1/2 scalings will use ScalePlaneDown2()
   if (dst_width == src_width && dst_height == src_height) {
@@ -3767,7 +3767,7 @@
               uint8* dst_u, int dst_stride_u,
               uint8* dst_v, int dst_stride_v,
               int dst_width, int dst_height,
-              FilterMode filtering) {
+              FilterModeEnum filtering) {
   if (!src_y || !src_u || !src_v || src_width <= 0 || src_height == 0 ||
       !dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
     return -1;
@@ -3832,7 +3832,7 @@
   int src_halfheight = (src_height + 1) >> 1;
   int dst_halfwidth = (dst_width + 1) >> 1;
   int dst_halfheight = (dst_height + 1) >> 1;
-  FilterMode filtering = interpolate ? kFilterBox : kFilterNone;
+  FilterModeEnum filtering = interpolate ? kFilterBox : kFilterNone;
 
   ScalePlane(src_y, src_stride_y, src_width, src_height,
              dst_y, dst_stride_y, dst_width, dst_height,
diff --git a/third_party/nestegg/README.webm b/third_party/nestegg/README.libvpx
similarity index 100%
rename from third_party/nestegg/README.webm
rename to third_party/nestegg/README.libvpx
diff --git a/third_party/x86inc/README.webm b/third_party/x86inc/README.libvpx
similarity index 100%
rename from third_party/x86inc/README.webm
rename to third_party/x86inc/README.libvpx
diff --git a/third_party/x86inc/x86inc.asm b/third_party/x86inc/x86inc.asm
index 9e4918a..5b22b94 100644
--- a/third_party/x86inc/x86inc.asm
+++ b/third_party/x86inc/x86inc.asm
@@ -592,16 +592,20 @@
         CAT_XDEFINE cglobaled_, %1, 1
     %endif
     %xdefine current_function %1
-    %ifidn __OUTPUT_FORMAT__,elf
-        global %1:function hidden
-    %elifidn __OUTPUT_FORMAT__,elf32
-        global %1:function hidden
-    %elifidn __OUTPUT_FORMAT__,elf64
-        global %1:function hidden
-    %elifidn __OUTPUT_FORMAT__,macho32
-        global %1:private_extern
-    %elifidn __OUTPUT_FORMAT__,macho64
-        global %1:private_extern
+    %ifdef CHROMIUM
+        %ifidn __OUTPUT_FORMAT__,elf
+            global %1:function hidden
+        %elifidn __OUTPUT_FORMAT__,elf32
+            global %1:function hidden
+        %elifidn __OUTPUT_FORMAT__,elf64
+            global %1:function hidden
+        %elifidn __OUTPUT_FORMAT__,macho32
+            global %1:private_extern
+        %elifidn __OUTPUT_FORMAT__,macho64
+            global %1:private_extern
+        %else
+            global %1
+        %endif
     %else
         global %1
     %endif
diff --git a/tools_common.h b/tools_common.h
index 549e895..2124882 100644
--- a/tools_common.h
+++ b/tools_common.h
@@ -25,15 +25,10 @@
 /* MSVS uses _f{seek,tell}i64. */
 #define fseeko _fseeki64
 #define ftello _ftelli64
-typedef long _off_t;  // NOLINT - MSVS compatible type
-typedef __int64 off_t;  // fseeki64 compatible type
-#define _OFF_T_DEFINED
 #elif defined(_WIN32)
-/* MinGW defines off_t as long and uses f{seek,tell}o64/off64_t for large
- * files. */
+/* MinGW uses f{seek,tell}o64 for large files. */
 #define fseeko fseeko64
 #define ftello ftello64
-#define off_t off64_t
 #endif  /* _WIN32 */
 
 #if CONFIG_OS_SUPPORT
@@ -50,7 +45,6 @@
 /* Use 32-bit file operations in WebM file format when building ARM
  * executables (.axf) with RVCT. */
 #if !CONFIG_OS_SUPPORT
-typedef long off_t;  /* NOLINT */
 #define fseeko fseek
 #define ftello ftell
 #endif  /* CONFIG_OS_SUPPORT */
@@ -90,7 +84,7 @@
 struct VpxInputContext {
   const char *filename;
   FILE *file;
-  off_t length;
+  int64_t length;
   struct FileTypeDetectionBuffer detect;
   enum VideoFileType file_type;
   uint32_t width;
diff --git a/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm
index e3ea91f..a8730aa 100644
--- a/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm
+++ b/vp8/common/arm/neon/buildintrapredictorsmby_neon.asm
@@ -26,6 +26,7 @@
 
 |vp8_build_intra_predictors_mby_neon_func| PROC
     push            {r4-r8, lr}
+    vpush           {d8-d15}
 
     cmp             r3, #0
     beq             case_dc_pred
@@ -37,8 +38,8 @@
     beq             case_tm_pred
 
 case_dc_pred
-    ldr             r4, [sp, #24]       ; Up
-    ldr             r5, [sp, #28]       ; Left
+    ldr             r4, [sp, #88]       ; Up
+    ldr             r5, [sp, #92]       ; Left
 
     ; Default the DC average to 128
     mov             r12, #128
@@ -143,6 +144,7 @@
     vst1.u8         {q0}, [r1]!
     vst1.u8         {q0}, [r1]!
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 case_v_pred
     ; Copy down above row
@@ -165,6 +167,7 @@
     vst1.u8         {q0}, [r1]!
     vst1.u8         {q0}, [r1]!
     vst1.u8         {q0}, [r1]!
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
 case_h_pred
@@ -224,6 +227,7 @@
     vst1.u8         {q2}, [r1]!
     vst1.u8         {q3}, [r1]!
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
 case_tm_pred
@@ -293,6 +297,7 @@
     subs            r12, r12, #1
     bne             case_tm_pred_loop
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
     ENDP
@@ -307,6 +312,7 @@
 
 |vp8_build_intra_predictors_mby_s_neon_func| PROC
     push            {r4-r8, lr}
+    vpush           {d8-d15}
 
     mov             r1, r0      ;   unsigned char *ypred_ptr = x->dst.y_buffer; //x->Predictor;
 
@@ -320,8 +326,8 @@
     beq             case_tm_pred_s
 
 case_dc_pred_s
-    ldr             r4, [sp, #24]       ; Up
-    ldr             r5, [sp, #28]       ; Left
+    ldr             r4, [sp, #88]       ; Up
+    ldr             r5, [sp, #92]       ; Left
 
     ; Default the DC average to 128
     mov             r12, #128
@@ -426,6 +432,7 @@
     vst1.u8         {q0}, [r1], r2
     vst1.u8         {q0}, [r1], r2
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 case_v_pred_s
     ; Copy down above row
@@ -448,6 +455,8 @@
     vst1.u8         {q0}, [r1], r2
     vst1.u8         {q0}, [r1], r2
     vst1.u8         {q0}, [r1], r2
+
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
 case_h_pred_s
@@ -507,6 +516,7 @@
     vst1.u8         {q2}, [r1], r2
     vst1.u8         {q3}, [r1], r2
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
 case_tm_pred_s
@@ -576,6 +586,7 @@
     subs            r12, r12, #1
     bne             case_tm_pred_loop_s
 
+    vpop            {d8-d15}
     pop             {r4-r8,pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm b/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm
index 6c29c55..3a39210 100644
--- a/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm
+++ b/vp8/common/arm/neon/idct_dequant_0_2x_neon.asm
@@ -22,6 +22,7 @@
 ; r3   stride
 |idct_dequant_0_2x_neon| PROC
     push            {r4, r5}
+    vpush           {d8-d15}
 
     add             r12, r2, #4
     vld1.32         {d2[0]}, [r2], r3
@@ -72,6 +73,7 @@
     vst1.32         {d4[1]}, [r2]
     vst1.32         {d10[1]}, [r0]
 
+    vpop            {d8-d15}
     pop             {r4, r5}
     bx              lr
 
diff --git a/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm b/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm
deleted file mode 100644
index d5dce63..0000000
--- a/vp8/common/arm/neon/idct_dequant_full_2x_neon.asm
+++ /dev/null
@@ -1,196 +0,0 @@
-;
-;  Copyright (c) 2010 The Webm project authors. All Rights Reserved.
-;
-;  Use of this source code is governed by a BSD-style license
-;  that can be found in the LICENSE file in the root of the source
-;  tree. An additional intellectual property rights grant can be found
-;  in the file PATENTS.  All contributing project authors may
-;  be found in the AUTHORS file in the root of the source tree.
-;
-
-
-    EXPORT  |idct_dequant_full_2x_neon|
-    ARM
-    REQUIRE8
-    PRESERVE8
-
-    AREA ||.text||, CODE, READONLY, ALIGN=2
-;void idct_dequant_full_2x_neon(short *q, short *dq,
-;                               unsigned char *dst, int stride);
-; r0    *q,
-; r1    *dq,
-; r2    *dst
-; r3    stride
-|idct_dequant_full_2x_neon| PROC
-    vld1.16         {q0, q1}, [r1]          ; dq (same l/r)
-    vld1.16         {q2, q3}, [r0]          ; l q
-    add             r0, r0, #32
-    vld1.16         {q4, q5}, [r0]          ; r q
-    add             r12, r2, #4
-
-    ; interleave the predictors
-    vld1.32         {d28[0]}, [r2],  r3     ; l pre
-    vld1.32         {d28[1]}, [r12], r3     ; r pre
-    vld1.32         {d29[0]}, [r2],  r3
-    vld1.32         {d29[1]}, [r12], r3
-    vld1.32         {d30[0]}, [r2],  r3
-    vld1.32         {d30[1]}, [r12], r3
-    vld1.32         {d31[0]}, [r2],  r3
-    vld1.32         {d31[1]}, [r12]
-
-    adr             r1, cospi8sqrt2minus1   ; pointer to the first constant
-
-    ; dequant: q[i] = q[i] * dq[i]
-    vmul.i16        q2, q2, q0
-    vmul.i16        q3, q3, q1
-    vmul.i16        q4, q4, q0
-    vmul.i16        q5, q5, q1
-
-    vld1.16         {d0}, [r1]
-
-    ; q2: l0r0  q3: l8r8
-    ; q4: l4r4  q5: l12r12
-    vswp            d5, d8
-    vswp            d7, d10
-
-    ; _CONSTANTS_ * 4,12 >> 16
-    ; q6:  4 * sinpi : c1/temp1
-    ; q7: 12 * sinpi : d1/temp2
-    ; q8:  4 * cospi
-    ; q9: 12 * cospi
-    vqdmulh.s16     q6, q4, d0[2]           ; sinpi8sqrt2
-    vqdmulh.s16     q7, q5, d0[2]
-    vqdmulh.s16     q8, q4, d0[0]           ; cospi8sqrt2minus1
-    vqdmulh.s16     q9, q5, d0[0]
-
-    vqadd.s16       q10, q2, q3             ; a1 = 0 + 8
-    vqsub.s16       q11, q2, q3             ; b1 = 0 - 8
-
-    ; vqdmulh only accepts signed values. this was a problem because
-    ; our constant had the high bit set, and was treated as a negative value.
-    ; vqdmulh also doubles the value before it shifts by 16. we need to
-    ; compensate for this. in the case of sinpi8sqrt2, the lowest bit is 0,
-    ; so we can shift the constant without losing precision. this avoids
-    ; shift again afterward, but also avoids the sign issue. win win!
-    ; for cospi8sqrt2minus1 the lowest bit is 1, so we lose precision if we
-    ; pre-shift it
-    vshr.s16        q8, q8, #1
-    vshr.s16        q9, q9, #1
-
-    ; q4:  4 +  4 * cospi : d1/temp1
-    ; q5: 12 + 12 * cospi : c1/temp2
-    vqadd.s16       q4, q4, q8
-    vqadd.s16       q5, q5, q9
-
-    ; c1 = temp1 - temp2
-    ; d1 = temp1 + temp2
-    vqsub.s16       q2, q6, q5
-    vqadd.s16       q3, q4, q7
-
-    ; [0]: a1+d1
-    ; [1]: b1+c1
-    ; [2]: b1-c1
-    ; [3]: a1-d1
-    vqadd.s16       q4, q10, q3
-    vqadd.s16       q5, q11, q2
-    vqsub.s16       q6, q11, q2
-    vqsub.s16       q7, q10, q3
-
-    ; rotate
-    vtrn.32         q4, q6
-    vtrn.32         q5, q7
-    vtrn.16         q4, q5
-    vtrn.16         q6, q7
-    ; idct loop 2
-    ; q4: l 0, 4, 8,12 r 0, 4, 8,12
-    ; q5: l 1, 5, 9,13 r 1, 5, 9,13
-    ; q6: l 2, 6,10,14 r 2, 6,10,14
-    ; q7: l 3, 7,11,15 r 3, 7,11,15
-
-    ; q8:  1 * sinpi : c1/temp1
-    ; q9:  3 * sinpi : d1/temp2
-    ; q10: 1 * cospi
-    ; q11: 3 * cospi
-    vqdmulh.s16     q8, q5, d0[2]           ; sinpi8sqrt2
-    vqdmulh.s16     q9, q7, d0[2]
-    vqdmulh.s16     q10, q5, d0[0]          ; cospi8sqrt2minus1
-    vqdmulh.s16     q11, q7, d0[0]
-
-    vqadd.s16       q2, q4, q6             ; a1 = 0 + 2
-    vqsub.s16       q3, q4, q6             ; b1 = 0 - 2
-
-    ; see note on shifting above
-    vshr.s16        q10, q10, #1
-    vshr.s16        q11, q11, #1
-
-    ; q10: 1 + 1 * cospi : d1/temp1
-    ; q11: 3 + 3 * cospi : c1/temp2
-    vqadd.s16       q10, q5, q10
-    vqadd.s16       q11, q7, q11
-
-    ; q8: c1 = temp1 - temp2
-    ; q9: d1 = temp1 + temp2
-    vqsub.s16       q8, q8, q11
-    vqadd.s16       q9, q10, q9
-
-    ; a1+d1
-    ; b1+c1
-    ; b1-c1
-    ; a1-d1
-    vqadd.s16       q4, q2, q9
-    vqadd.s16       q5, q3, q8
-    vqsub.s16       q6, q3, q8
-    vqsub.s16       q7, q2, q9
-
-    ; +4 >> 3 (rounding)
-    vrshr.s16       q4, q4, #3              ; lo
-    vrshr.s16       q5, q5, #3
-    vrshr.s16       q6, q6, #3              ; hi
-    vrshr.s16       q7, q7, #3
-
-    vtrn.32         q4, q6
-    vtrn.32         q5, q7
-    vtrn.16         q4, q5
-    vtrn.16         q6, q7
-
-    ; adding pre
-    ; input is still packed. pre was read interleaved
-    vaddw.u8        q4, q4, d28
-    vaddw.u8        q5, q5, d29
-    vaddw.u8        q6, q6, d30
-    vaddw.u8        q7, q7, d31
-
-    vmov.i16        q14, #0
-    vmov            q15, q14
-    vst1.16         {q14, q15}, [r0]        ; write over high input
-    sub             r0, r0, #32
-    vst1.16         {q14, q15}, [r0]        ; write over low input
-
-    sub             r2, r2, r3, lsl #2      ; dst - 4*stride
-    add             r1, r2, #4              ; hi
-
-    ;saturate and narrow
-    vqmovun.s16     d0, q4                  ; lo
-    vqmovun.s16     d1, q5
-    vqmovun.s16     d2, q6                  ; hi
-    vqmovun.s16     d3, q7
-
-    vst1.32         {d0[0]}, [r2], r3       ; lo
-    vst1.32         {d0[1]}, [r1], r3       ; hi
-    vst1.32         {d1[0]}, [r2], r3
-    vst1.32         {d1[1]}, [r1], r3
-    vst1.32         {d2[0]}, [r2], r3
-    vst1.32         {d2[1]}, [r1], r3
-    vst1.32         {d3[0]}, [r2]
-    vst1.32         {d3[1]}, [r1]
-
-    bx             lr
-
-    ENDP           ; |idct_dequant_full_2x_neon|
-
-; Constant Pool
-cospi8sqrt2minus1 DCD 0x4e7b
-; because the lowest bit in 0x8a8c is 0, we can pre-shift this
-sinpi8sqrt2       DCD 0x4546
-
-    END
diff --git a/vp8/common/arm/neon/idct_dequant_full_2x_neon.c b/vp8/common/arm/neon/idct_dequant_full_2x_neon.c
new file mode 100644
index 0000000..a60ed46
--- /dev/null
+++ b/vp8/common/arm/neon/idct_dequant_full_2x_neon.c
@@ -0,0 +1,185 @@
+/*
+ *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <arm_neon.h>
+
+static const int16_t cospi8sqrt2minus1 = 20091;
+static const int16_t sinpi8sqrt2       = 17734;
+// because the lowest bit in 0x8a8c is 0, we can pre-shift this
+
+void idct_dequant_full_2x_neon(
+        int16_t *q,
+        int16_t *dq,
+        unsigned char *dst,
+        int stride) {
+    unsigned char *dst0, *dst1;
+    int32x2_t d28, d29, d30, d31;
+    int16x8_t q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11;
+    int16x8_t qEmpty = vdupq_n_s16(0);
+    int32x4x2_t q2tmp0, q2tmp1;
+    int16x8x2_t q2tmp2, q2tmp3;
+    int16x4_t dLow0, dLow1, dHigh0, dHigh1;
+
+    d28 = d29 = d30 = d31 = vdup_n_s32(0);
+
+    // load dq
+    q0 = vld1q_s16(dq);
+    dq += 8;
+    q1 = vld1q_s16(dq);
+
+    // load q
+    q2 = vld1q_s16(q);
+    vst1q_s16(q, qEmpty);
+    q += 8;
+    q3 = vld1q_s16(q);
+    vst1q_s16(q, qEmpty);
+    q += 8;
+    q4 = vld1q_s16(q);
+    vst1q_s16(q, qEmpty);
+    q += 8;
+    q5 = vld1q_s16(q);
+    vst1q_s16(q, qEmpty);
+
+    // load src from dst
+    dst0 = dst;
+    dst1 = dst + 4;
+    d28 = vld1_lane_s32((const int32_t *)dst0, d28, 0);
+    dst0 += stride;
+    d28 = vld1_lane_s32((const int32_t *)dst1, d28, 1);
+    dst1 += stride;
+    d29 = vld1_lane_s32((const int32_t *)dst0, d29, 0);
+    dst0 += stride;
+    d29 = vld1_lane_s32((const int32_t *)dst1, d29, 1);
+    dst1 += stride;
+
+    d30 = vld1_lane_s32((const int32_t *)dst0, d30, 0);
+    dst0 += stride;
+    d30 = vld1_lane_s32((const int32_t *)dst1, d30, 1);
+    dst1 += stride;
+    d31 = vld1_lane_s32((const int32_t *)dst0, d31, 0);
+    d31 = vld1_lane_s32((const int32_t *)dst1, d31, 1);
+
+    q2 = vmulq_s16(q2, q0);
+    q3 = vmulq_s16(q3, q1);
+    q4 = vmulq_s16(q4, q0);
+    q5 = vmulq_s16(q5, q1);
+
+    // vswp
+    dLow0 = vget_low_s16(q2);
+    dHigh0 = vget_high_s16(q2);
+    dLow1 = vget_low_s16(q4);
+    dHigh1 = vget_high_s16(q4);
+    q2 = vcombine_s16(dLow0, dLow1);
+    q4 = vcombine_s16(dHigh0, dHigh1);
+
+    dLow0 = vget_low_s16(q3);
+    dHigh0 = vget_high_s16(q3);
+    dLow1 = vget_low_s16(q5);
+    dHigh1 = vget_high_s16(q5);
+    q3 = vcombine_s16(dLow0, dLow1);
+    q5 = vcombine_s16(dHigh0, dHigh1);
+
+    q6 = vqdmulhq_n_s16(q4, sinpi8sqrt2);
+    q7 = vqdmulhq_n_s16(q5, sinpi8sqrt2);
+    q8 = vqdmulhq_n_s16(q4, cospi8sqrt2minus1);
+    q9 = vqdmulhq_n_s16(q5, cospi8sqrt2minus1);
+
+    q10 = vqaddq_s16(q2, q3);
+    q11 = vqsubq_s16(q2, q3);
+
+    q8 = vshrq_n_s16(q8, 1);
+    q9 = vshrq_n_s16(q9, 1);
+
+    q4 = vqaddq_s16(q4, q8);
+    q5 = vqaddq_s16(q5, q9);
+
+    q2 = vqsubq_s16(q6, q5);
+    q3 = vqaddq_s16(q7, q4);
+
+    q4 = vqaddq_s16(q10, q3);
+    q5 = vqaddq_s16(q11, q2);
+    q6 = vqsubq_s16(q11, q2);
+    q7 = vqsubq_s16(q10, q3);
+
+    q2tmp0 = vtrnq_s32(vreinterpretq_s32_s16(q4), vreinterpretq_s32_s16(q6));
+    q2tmp1 = vtrnq_s32(vreinterpretq_s32_s16(q5), vreinterpretq_s32_s16(q7));
+    q2tmp2 = vtrnq_s16(vreinterpretq_s16_s32(q2tmp0.val[0]),
+                       vreinterpretq_s16_s32(q2tmp1.val[0]));
+    q2tmp3 = vtrnq_s16(vreinterpretq_s16_s32(q2tmp0.val[1]),
+                       vreinterpretq_s16_s32(q2tmp1.val[1]));
+
+    // loop 2
+    q8  = vqdmulhq_n_s16(q2tmp2.val[1], sinpi8sqrt2);
+    q9  = vqdmulhq_n_s16(q2tmp3.val[1], sinpi8sqrt2);
+    q10 = vqdmulhq_n_s16(q2tmp2.val[1], cospi8sqrt2minus1);
+    q11 = vqdmulhq_n_s16(q2tmp3.val[1], cospi8sqrt2minus1);
+
+    q2 = vqaddq_s16(q2tmp2.val[0], q2tmp3.val[0]);
+    q3 = vqsubq_s16(q2tmp2.val[0], q2tmp3.val[0]);
+
+    q10 = vshrq_n_s16(q10, 1);
+    q11 = vshrq_n_s16(q11, 1);
+
+    q10 = vqaddq_s16(q2tmp2.val[1], q10);
+    q11 = vqaddq_s16(q2tmp3.val[1], q11);
+
+    q8 = vqsubq_s16(q8, q11);
+    q9 = vqaddq_s16(q9, q10);
+
+    q4 = vqaddq_s16(q2, q9);
+    q5 = vqaddq_s16(q3, q8);
+    q6 = vqsubq_s16(q3, q8);
+    q7 = vqsubq_s16(q2, q9);
+
+    q4 = vrshrq_n_s16(q4, 3);
+    q5 = vrshrq_n_s16(q5, 3);
+    q6 = vrshrq_n_s16(q6, 3);
+    q7 = vrshrq_n_s16(q7, 3);
+
+    q2tmp0 = vtrnq_s32(vreinterpretq_s32_s16(q4), vreinterpretq_s32_s16(q6));
+    q2tmp1 = vtrnq_s32(vreinterpretq_s32_s16(q5), vreinterpretq_s32_s16(q7));
+    q2tmp2 = vtrnq_s16(vreinterpretq_s16_s32(q2tmp0.val[0]),
+                       vreinterpretq_s16_s32(q2tmp1.val[0]));
+    q2tmp3 = vtrnq_s16(vreinterpretq_s16_s32(q2tmp0.val[1]),
+                       vreinterpretq_s16_s32(q2tmp1.val[1]));
+
+    q4 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q2tmp2.val[0]),
+                                          vreinterpret_u8_s32(d28)));
+    q5 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q2tmp2.val[1]),
+                                          vreinterpret_u8_s32(d29)));
+    q6 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q2tmp3.val[0]),
+                                          vreinterpret_u8_s32(d30)));
+    q7 = vreinterpretq_s16_u16(vaddw_u8(vreinterpretq_u16_s16(q2tmp3.val[1]),
+                                          vreinterpret_u8_s32(d31)));
+
+    d28 = vreinterpret_s32_u8(vqmovun_s16(q4));
+    d29 = vreinterpret_s32_u8(vqmovun_s16(q5));
+    d30 = vreinterpret_s32_u8(vqmovun_s16(q6));
+    d31 = vreinterpret_s32_u8(vqmovun_s16(q7));
+
+    dst0 = dst;
+    dst1 = dst + 4;
+    vst1_lane_s32((int32_t *)dst0, d28, 0);
+    dst0 += stride;
+    vst1_lane_s32((int32_t *)dst1, d28, 1);
+    dst1 += stride;
+    vst1_lane_s32((int32_t *)dst0, d29, 0);
+    dst0 += stride;
+    vst1_lane_s32((int32_t *)dst1, d29, 1);
+    dst1 += stride;
+
+    vst1_lane_s32((int32_t *)dst0, d30, 0);
+    dst0 += stride;
+    vst1_lane_s32((int32_t *)dst1, d30, 1);
+    dst1 += stride;
+    vst1_lane_s32((int32_t *)dst0, d31, 0);
+    vst1_lane_s32((int32_t *)dst1, d31, 1);
+    return;
+}
diff --git a/vp8/common/arm/neon/loopfilter_neon.asm b/vp8/common/arm/neon/loopfilter_neon.asm
index e44be0a..c4f09c7 100644
--- a/vp8/common/arm/neon/loopfilter_neon.asm
+++ b/vp8/common/arm/neon/loopfilter_neon.asm
@@ -24,10 +24,12 @@
 ; sp    unsigned char thresh,
 |vp8_loop_filter_horizontal_edge_y_neon| PROC
     push        {lr}
+    vpush       {d8-d15}
+
     vdup.u8     q0, r2                     ; duplicate blimit
     vdup.u8     q1, r3                     ; duplicate limit
     sub         r2, r0, r1, lsl #2         ; move src pointer down by 4 lines
-    ldr         r3, [sp, #4]               ; load thresh
+    ldr         r3, [sp, #68]              ; load thresh
     add         r12, r2, r1
     add         r1, r1, r1
 
@@ -52,6 +54,7 @@
     vst1.u8     {q7}, [r2@128], r1              ; store oq0
     vst1.u8     {q8}, [r12@128], r1             ; store oq1
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_loop_filter_horizontal_edge_y_neon|
 
@@ -64,10 +67,12 @@
 ; sp+4  unsigned char *v
 |vp8_loop_filter_horizontal_edge_uv_neon| PROC
     push        {lr}
+    vpush       {d8-d15}
+
     vdup.u8     q0, r2                      ; duplicate blimit
     vdup.u8     q1, r3                      ; duplicate limit
-    ldr         r12, [sp, #4]               ; load thresh
-    ldr         r2, [sp, #8]                ; load v ptr
+    ldr         r12, [sp, #68]              ; load thresh
+    ldr         r2, [sp, #72]               ; load v ptr
     vdup.u8     q2, r12                     ; duplicate thresh
 
     sub         r3, r0, r1, lsl #2          ; move u pointer down by 4 lines
@@ -104,6 +109,7 @@
     vst1.u8     {d16}, [r0@64]                 ; store u oq1
     vst1.u8     {d17}, [r2@64]                 ; store v oq1
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_loop_filter_horizontal_edge_uv_neon|
 
@@ -120,11 +126,13 @@
 
 |vp8_loop_filter_vertical_edge_y_neon| PROC
     push        {lr}
+    vpush       {d8-d15}
+
     vdup.u8     q0, r2                     ; duplicate blimit
     vdup.u8     q1, r3                     ; duplicate limit
     sub         r2, r0, #4                 ; src ptr down by 4 columns
     add         r1, r1, r1
-    ldr         r3, [sp, #4]               ; load thresh
+    ldr         r3, [sp, #68]              ; load thresh
     add         r12, r2, r1, asr #1
 
     vld1.u8     {d6}, [r2], r1
@@ -194,6 +202,7 @@
     vst4.8      {d14[6], d15[6], d16[6], d17[6]}, [r0]
     vst4.8      {d14[7], d15[7], d16[7], d17[7]}, [r12]
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_loop_filter_vertical_edge_y_neon|
 
@@ -210,9 +219,11 @@
 ; sp+4  unsigned char *v
 |vp8_loop_filter_vertical_edge_uv_neon| PROC
     push        {lr}
+    vpush       {d8-d15}
+
     vdup.u8     q0, r2                      ; duplicate blimit
     sub         r12, r0, #4                 ; move u pointer down by 4 columns
-    ldr         r2, [sp, #8]                ; load v ptr
+    ldr         r2, [sp, #72]               ; load v ptr
     vdup.u8     q1, r3                      ; duplicate limit
     sub         r3, r2, #4                  ; move v pointer down by 4 columns
 
@@ -233,7 +244,7 @@
     vld1.u8     {d20}, [r12]
     vld1.u8     {d21}, [r3]
 
-    ldr        r12, [sp, #4]               ; load thresh
+    ldr        r12, [sp, #68]              ; load thresh
 
     ;transpose to 8x16 matrix
     vtrn.32     q3, q7
@@ -281,6 +292,7 @@
     vst4.8      {d10[7], d11[7], d12[7], d13[7]}, [r0]
     vst4.8      {d14[7], d15[7], d16[7], d17[7]}, [r2]
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_loop_filter_vertical_edge_uv_neon|
 
diff --git a/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm
index adf848b..6eb0651 100644
--- a/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm
+++ b/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.asm
@@ -9,7 +9,6 @@
 ;
 
 
-    ;EXPORT  |vp8_loop_filter_simple_horizontal_edge_neon|
     EXPORT  |vp8_loop_filter_bhs_neon|
     EXPORT  |vp8_loop_filter_mbhs_neon|
     ARM
@@ -22,7 +21,7 @@
 ; q1    limit, PRESERVE
 
 |vp8_loop_filter_simple_horizontal_edge_neon| PROC
-
+    vpush       {d8-d15}
     sub         r3, r0, r1, lsl #1          ; move src pointer down by 2 lines
 
     vld1.u8     {q7}, [r0@128], r1          ; q0
@@ -82,6 +81,7 @@
     vst1.u8     {q6}, [r3@128]              ; store op0
     vst1.u8     {q7}, [r0@128]              ; store oq0
 
+    vpop        {d8-d15}
     bx          lr
     ENDP        ; |vp8_loop_filter_simple_horizontal_edge_neon|
 
diff --git a/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm
index e690df2..78d13c8 100644
--- a/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm
+++ b/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.asm
@@ -9,7 +9,6 @@
 ;
 
 
-    ;EXPORT  |vp8_loop_filter_simple_vertical_edge_neon|
     EXPORT |vp8_loop_filter_bvs_neon|
     EXPORT |vp8_loop_filter_mbvs_neon|
     ARM
@@ -22,6 +21,8 @@
 ; q1    limit, PRESERVE
 
 |vp8_loop_filter_simple_vertical_edge_neon| PROC
+    vpush       {d8-d15}
+
     sub         r0, r0, #2                  ; move src pointer down by 2 columns
     add         r12, r1, r1
     add         r3, r0, r1
@@ -120,6 +121,7 @@
     vst2.8      {d14[6], d15[6]}, [r0], r12
     vst2.8      {d14[7], d15[7]}, [r3]
 
+    vpop        {d8-d15}
     bx          lr
     ENDP        ; |vp8_loop_filter_simple_vertical_edge_neon|
 
diff --git a/vp8/common/arm/neon/mbloopfilter_neon.asm b/vp8/common/arm/neon/mbloopfilter_neon.asm
index f41c156..d200c30 100644
--- a/vp8/common/arm/neon/mbloopfilter_neon.asm
+++ b/vp8/common/arm/neon/mbloopfilter_neon.asm
@@ -28,8 +28,10 @@
 ; sp    unsigned char thresh,
 |vp8_mbloop_filter_horizontal_edge_y_neon| PROC
     push        {lr}
+    vpush       {d8-d15}
+
     add         r1, r1, r1                  ; double stride
-    ldr         r12, [sp, #4]               ; load thresh
+    ldr         r12, [sp, #68]              ; load thresh
     sub         r0, r0, r1, lsl #1          ; move src pointer down by 4 lines
     vdup.u8     q2, r12                     ; thresh
     add         r12, r0, r1,  lsr #1        ; move src pointer up by 1 line
@@ -55,6 +57,7 @@
     vst1.u8     {q8}, [r12@128]            ; store oq1
     vst1.u8     {q9}, [r0@128]             ; store oq2
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_mbloop_filter_horizontal_edge_y_neon|
 
@@ -72,10 +75,12 @@
 
 |vp8_mbloop_filter_horizontal_edge_uv_neon| PROC
     push        {lr}
-    ldr         r12, [sp, #4]                 ; load thresh
+    vpush       {d8-d15}
+
+    ldr         r12, [sp, #68]                ; load thresh
     sub         r0, r0, r1, lsl #2            ; move u pointer down by 4 lines
     vdup.u8     q2, r12                       ; thresh
-    ldr         r12, [sp, #8]                 ; load v ptr
+    ldr         r12, [sp, #72]                ; load v ptr
     sub         r12, r12, r1, lsl #2          ; move v pointer down by 4 lines
 
     vld1.u8     {d6}, [r0@64], r1              ; p3
@@ -116,6 +121,7 @@
     vst1.u8     {d18}, [r0@64], r1             ; store u oq2
     vst1.u8     {d19}, [r12@64], r1             ; store v oq2
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_mbloop_filter_horizontal_edge_uv_neon|
 
@@ -130,7 +136,9 @@
 ; sp    unsigned char thresh,
 |vp8_mbloop_filter_vertical_edge_y_neon| PROC
     push        {lr}
-    ldr         r12, [sp, #4]               ; load thresh
+    vpush       {d8-d15}
+
+    ldr         r12, [sp, #68]              ; load thresh
     sub         r0, r0, #4                  ; move src pointer down by 4 columns
     vdup.s8     q2, r12                     ; thresh
     add         r12, r0, r1, lsl #3         ; move src pointer down by 8 lines
@@ -208,6 +216,7 @@
     vst1.8      {d20}, [r0]
     vst1.8      {d21}, [r12]
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_mbloop_filter_vertical_edge_y_neon|
 
@@ -224,10 +233,12 @@
 ; sp+4  unsigned char *v
 |vp8_mbloop_filter_vertical_edge_uv_neon| PROC
     push        {lr}
-    ldr         r12, [sp, #4]               ; load thresh
+    vpush       {d8-d15}
+
+    ldr         r12, [sp, #68]              ; load thresh
     sub         r0, r0, #4                  ; move u pointer down by 4 columns
     vdup.u8     q2, r12                     ; thresh
-    ldr         r12, [sp, #8]               ; load v ptr
+    ldr         r12, [sp, #72]              ; load v ptr
     sub         r12, r12, #4                ; move v pointer down by 4 columns
 
     vld1.u8     {d6}, [r0], r1              ;load u data
@@ -303,6 +314,7 @@
     vst1.8      {d20}, [r0]
     vst1.8      {d21}, [r12]
 
+    vpop        {d8-d15}
     pop         {pc}
     ENDP        ; |vp8_mbloop_filter_vertical_edge_uv_neon|
 
diff --git a/vp8/common/arm/neon/sad16_neon.asm b/vp8/common/arm/neon/sad16_neon.asm
index d7c590e..7197e56 100644
--- a/vp8/common/arm/neon/sad16_neon.asm
+++ b/vp8/common/arm/neon/sad16_neon.asm
@@ -24,6 +24,7 @@
 ; r3    int  ref_stride
 |vp8_sad16x16_neon| PROC
 ;;
+    vpush           {d8-d15}
     vld1.8          {q0}, [r0], r1
     vld1.8          {q4}, [r2], r3
 
@@ -132,6 +133,7 @@
 
     vmov.32         r0, d0[0]
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
@@ -143,6 +145,8 @@
 ;    unsigned char *ref_ptr,
 ;    int  ref_stride)
 |vp8_sad16x8_neon| PROC
+    vpush           {d8-d15}
+
     vld1.8          {q0}, [r0], r1
     vld1.8          {q4}, [r2], r3
 
@@ -200,6 +204,7 @@
 
     vmov.32         r0, d0[0]
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
diff --git a/vp8/common/arm/neon/sad8_neon.asm b/vp8/common/arm/neon/sad8_neon.asm
index 23ba6df..6b849d9 100644
--- a/vp8/common/arm/neon/sad8_neon.asm
+++ b/vp8/common/arm/neon/sad8_neon.asm
@@ -25,6 +25,7 @@
 ;    int  ref_stride)
 
 |vp8_sad8x8_neon| PROC
+    vpush           {d8-d15}
     vld1.8          {d0}, [r0], r1
     vld1.8          {d8}, [r2], r3
 
@@ -70,6 +71,7 @@
 
     vmov.32         r0, d0[0]
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
@@ -82,6 +84,7 @@
 ;    int  ref_stride)
 
 |vp8_sad8x16_neon| PROC
+    vpush           {d8-d15}
     vld1.8          {d0}, [r0], r1
     vld1.8          {d8}, [r2], r3
 
@@ -167,6 +170,7 @@
 
     vmov.32         r0, d0[0]
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
@@ -179,6 +183,7 @@
 ;    int  ref_stride)
 
 |vp8_sad4x4_neon| PROC
+    vpush           {d8-d15}
     vld1.8          {d0}, [r0], r1
     vld1.8          {d8}, [r2], r3
 
@@ -202,6 +207,7 @@
     vpaddl.u32      d0, d1
     vmov.32         r0, d0[0]
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
diff --git a/vp8/common/arm/neon/save_reg_neon.asm b/vp8/common/arm/neon/save_reg_neon.asm
deleted file mode 100644
index fd7002e..0000000
--- a/vp8/common/arm/neon/save_reg_neon.asm
+++ /dev/null
@@ -1,36 +0,0 @@
-;
-;  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-;
-;  Use of this source code is governed by a BSD-style license
-;  that can be found in the LICENSE file in the root of the source
-;  tree. An additional intellectual property rights grant can be found
-;  in the file PATENTS.  All contributing project authors may
-;  be found in the AUTHORS file in the root of the source tree.
-;
-
-
-    EXPORT  |vp8_push_neon|
-    EXPORT  |vp8_pop_neon|
-
-    ARM
-    REQUIRE8
-    PRESERVE8
-
-    AREA ||.text||, CODE, READONLY, ALIGN=2
-
-|vp8_push_neon| PROC
-    vst1.i64            {d8, d9, d10, d11}, [r0]!
-    vst1.i64            {d12, d13, d14, d15}, [r0]!
-    bx              lr
-
-    ENDP
-
-|vp8_pop_neon| PROC
-    vld1.i64            {d8, d9, d10, d11}, [r0]!
-    vld1.i64            {d12, d13, d14, d15}, [r0]!
-    bx              lr
-
-    ENDP
-
-    END
-
diff --git a/vp8/common/arm/neon/shortidct4x4llm_neon.asm b/vp8/common/arm/neon/shortidct4x4llm_neon.asm
index 67d2ab0..87ca887 100644
--- a/vp8/common/arm/neon/shortidct4x4llm_neon.asm
+++ b/vp8/common/arm/neon/shortidct4x4llm_neon.asm
@@ -37,12 +37,14 @@
 ; result of the multiplication that is needed in IDCT.
 
 |vp8_short_idct4x4llm_neon| PROC
+    vpush           {d8-d15}
+
     adr             r12, idct_coeff
     vld1.16         {q1, q2}, [r0]
     vld1.16         {d0}, [r12]
 
     vswp            d3, d4                  ;q2(vp[4] vp[12])
-    ldr             r0, [sp]                ; stride
+    ldr             r0, [sp, #64]           ; stride
 
     vqdmulh.s16     q3, q2, d0[2]
     vqdmulh.s16     q4, q2, d0[0]
@@ -125,6 +127,7 @@
     vst1.32         d2[0], [r3], r0
     vst1.32         d2[1], [r3], r0
 
+    vpop            {d8-d15}
     bx              lr
 
     ENDP
diff --git a/vp8/common/arm/neon/sixtappredict16x16_neon.asm b/vp8/common/arm/neon/sixtappredict16x16_neon.asm
index 9fdafd3..dd27719 100644
--- a/vp8/common/arm/neon/sixtappredict16x16_neon.asm
+++ b/vp8/common/arm/neon/sixtappredict16x16_neon.asm
@@ -43,10 +43,11 @@
 
 |vp8_sixtap_predict16x16_neon| PROC
     push            {r4-r5, lr}
+    vpush           {d8-d15}
 
     adr             r12, filter16_coeff
-    ldr             r4, [sp, #12]           ;load parameters from stack
-    ldr             r5, [sp, #16]           ;load parameters from stack
+    ldr             r4, [sp, #76]           ;load parameters from stack
+    ldr             r5, [sp, #80]           ;load parameters from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_filter16x16_only
@@ -291,6 +292,8 @@
     bne filt_blk2d_sp16x16_outloop_neon
 
     add             sp, sp, #336
+
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;--------------------
@@ -384,6 +387,7 @@
 
     bne             filt_blk2d_fpo16x16_loop_neon
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;--------------------
@@ -482,6 +486,7 @@
 
     bne filt_blk2d_spo16x16_outloop_neon
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/sixtappredict4x4_neon.asm b/vp8/common/arm/neon/sixtappredict4x4_neon.asm
index a4222bc..e32e713 100644
--- a/vp8/common/arm/neon/sixtappredict4x4_neon.asm
+++ b/vp8/common/arm/neon/sixtappredict4x4_neon.asm
@@ -35,10 +35,11 @@
 
 |vp8_sixtap_predict4x4_neon| PROC
     push            {r4, lr}
+    vpush           {d8-d15}
 
     adr             r12, filter4_coeff
-    ldr             r4, [sp, #8]            ;load parameters from stack
-    ldr             lr, [sp, #12]           ;load parameters from stack
+    ldr             r4, [sp, #72]            ;load parameters from stack
+    ldr             lr, [sp, #76]           ;load parameters from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_filter4x4_only
@@ -261,6 +262,7 @@
     vst1.32         {d4[0]}, [r1]
     vst1.32         {d4[1]}, [r2]
 
+    vpop            {d8-d15}
     pop             {r4, pc}
 
 
@@ -348,6 +350,7 @@
     vst1.32         {d28[0]}, [r1]
     vst1.32         {d28[1]}, [r2]
 
+    vpop            {d8-d15}
     pop             {r4, pc}
 
 
@@ -413,6 +416,7 @@
     vst1.32         {d4[0]}, [r1]
     vst1.32         {d4[1]}, [r2]
 
+    vpop            {d8-d15}
     pop             {r4, pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/sixtappredict8x4_neon.asm b/vp8/common/arm/neon/sixtappredict8x4_neon.asm
index a57ec01..d19bf89 100644
--- a/vp8/common/arm/neon/sixtappredict8x4_neon.asm
+++ b/vp8/common/arm/neon/sixtappredict8x4_neon.asm
@@ -35,10 +35,11 @@
 
 |vp8_sixtap_predict8x4_neon| PROC
     push            {r4-r5, lr}
+    vpush           {d8-d15}
 
     adr             r12, filter8_coeff
-    ldr             r4, [sp, #12]           ;load parameters from stack
-    ldr             r5, [sp, #16]           ;load parameters from stack
+    ldr             r4, [sp, #76]           ;load parameters from stack
+    ldr             r5, [sp, #80]           ;load parameters from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_filter8x4_only
@@ -297,6 +298,8 @@
     vst1.u8         {d9}, [r4], r5
 
     add             sp, sp, #32
+
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;--------------------
@@ -392,6 +395,7 @@
     vst1.u8         {d24}, [r4], r5
     vst1.u8         {d25}, [r4], r5
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;---------------------
@@ -464,6 +468,7 @@
     vst1.u8         {d8}, [r4], r5
     vst1.u8         {d9}, [r4], r5
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/sixtappredict8x8_neon.asm b/vp8/common/arm/neon/sixtappredict8x8_neon.asm
index 00ed5ae..4b04925 100644
--- a/vp8/common/arm/neon/sixtappredict8x8_neon.asm
+++ b/vp8/common/arm/neon/sixtappredict8x8_neon.asm
@@ -35,11 +35,11 @@
 
 |vp8_sixtap_predict8x8_neon| PROC
     push            {r4-r5, lr}
-
+    vpush           {d8-d15}
     adr             r12, filter8_coeff
 
-    ldr             r4, [sp, #12]           ;load parameters from stack
-    ldr             r5, [sp, #16]           ;load parameters from stack
+    ldr             r4, [sp, #76]           ;load parameters from stack
+    ldr             r5, [sp, #80]           ;load parameters from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_filter8x8_only
@@ -324,6 +324,8 @@
     bne filt_blk2d_sp8x8_loop_neon
 
     add             sp, sp, #64
+
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;---------------------
@@ -428,6 +430,7 @@
 
     bne             filt_blk2d_fpo8x8_loop_neon
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
 ;---------------------
@@ -515,6 +518,7 @@
 
     bne filt_blk2d_spo8x8_loop_neon
 
+    vpop            {d8-d15}
     pop             {r4-r5,pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/variance_neon.asm b/vp8/common/arm/neon/variance_neon.asm
index e3b4832..8ecad72 100644
--- a/vp8/common/arm/neon/variance_neon.asm
+++ b/vp8/common/arm/neon/variance_neon.asm
@@ -26,6 +26,7 @@
 ; r3    int  recon_stride
 ; stack unsigned int *sse
 |vp8_variance16x16_neon| PROC
+    vpush           {q5}
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
     vmov.i8         q10, #0
@@ -67,7 +68,7 @@
     vadd.u32        q10, q9, q10                ;accumulate sse
     vpaddl.s32      q0, q8                      ;accumulate sum
 
-    ldr             r12, [sp]                   ;load *sse from stack
+    ldr             r12, [sp, #16]              ;load *sse from stack
 
     vpaddl.u32      q1, q10
     vadd.s64        d0, d0, d1
@@ -87,6 +88,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {q5}
     bx              lr
 
     ENDP
@@ -99,6 +102,8 @@
 ;    int  recon_stride,
 ;   unsigned int *sse)
 |vp8_variance16x8_neon| PROC
+    vpush           {q5}
+
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
     vmov.i8         q10, #0
@@ -137,7 +142,7 @@
     vadd.u32        q10, q9, q10                ;accumulate sse
     vpaddl.s32      q0, q8                      ;accumulate sum
 
-    ldr             r12, [sp]                   ;load *sse from stack
+    ldr             r12, [sp, #16]              ;load *sse from stack
 
     vpaddl.u32      q1, q10
     vadd.s64        d0, d0, d1
@@ -149,6 +154,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {q5}
     bx              lr
 
     ENDP
@@ -162,6 +169,8 @@
 ;   unsigned int *sse)
 
 |vp8_variance8x16_neon| PROC
+    vpush           {q5}
+
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
     vmov.i8         q10, #0
@@ -192,7 +201,7 @@
     vadd.u32        q10, q9, q10                ;accumulate sse
     vpaddl.s32      q0, q8                      ;accumulate sum
 
-    ldr             r12, [sp]                   ;load *sse from stack
+    ldr             r12, [sp, #16]              ;load *sse from stack
 
     vpaddl.u32      q1, q10
     vadd.s64        d0, d0, d1
@@ -204,6 +213,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {q5}
     bx              lr
 
     ENDP
@@ -215,6 +226,8 @@
 ; r3    int  recon_stride
 ; stack unsigned int *sse
 |vp8_variance8x8_neon| PROC
+    vpush           {q5}
+
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
     vmov.i8         q10, #0
@@ -257,7 +270,7 @@
     vadd.u32        q10, q9, q10                ;accumulate sse
     vpaddl.s32      q0, q8                      ;accumulate sum
 
-    ldr             r12, [sp]                   ;load *sse from stack
+    ldr             r12, [sp, #16]              ;load *sse from stack
 
     vpaddl.u32      q1, q10
     vadd.s64        d0, d0, d1
@@ -269,6 +282,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {q5}
     bx              lr
 
     ENDP
diff --git a/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm b/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm
index 9d22c52..adc5b7e 100644
--- a/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm
+++ b/vp8/common/arm/neon/vp8_subpixelvariance16x16_neon.asm
@@ -31,11 +31,12 @@
 
 |vp8_sub_pixel_variance16x16_neon_func| PROC
     push            {r4-r6, lr}
+    vpush           {d8-d15}
 
     adr             r12, bilinear_taps_coeff
-    ldr             r4, [sp, #16]           ;load *dst_ptr from stack
-    ldr             r5, [sp, #20]           ;load dst_pixels_per_line from stack
-    ldr             r6, [sp, #24]           ;load *sse from stack
+    ldr             r4, [sp, #80]           ;load *dst_ptr from stack
+    ldr             r5, [sp, #84]           ;load dst_pixels_per_line from stack
+    ldr             r6, [sp, #88]           ;load *sse from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_bfilter16x16_only
@@ -416,6 +417,7 @@
     add             sp, sp, #528
     vmov.32         r0, d0[0]                   ;return
 
+    vpop            {d8-d15}
     pop             {r4-r6,pc}
 
     ENDP
diff --git a/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm b/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm
index 155be4f..b0829af 100644
--- a/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm
+++ b/vp8/common/arm/neon/vp8_subpixelvariance16x16s_neon.asm
@@ -31,9 +31,10 @@
 ;================================================
 |vp8_variance_halfpixvar16x16_h_neon| PROC
     push            {lr}
+    vpush           {d8-d15}
 
     mov             r12, #4                  ;loop counter
-    ldr             lr, [sp, #4]           ;load *sse from stack
+    ldr             lr, [sp, #68]            ;load *sse from stack
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
     vmov.i8         q10, #0
@@ -116,6 +117,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {d8-d15}
     pop             {pc}
     ENDP
 
@@ -131,11 +134,12 @@
 ;================================================
 |vp8_variance_halfpixvar16x16_v_neon| PROC
     push            {lr}
+    vpush           {d8-d15}
 
     mov             r12, #4                     ;loop counter
 
     vld1.u8         {q0}, [r0], r1              ;load src data
-    ldr             lr, [sp, #4]                ;load *sse from stack
+    ldr             lr, [sp, #68]               ;load *sse from stack
 
     vmov.i8         q8, #0                      ;q8 - sum
     vmov.i8         q9, #0                      ;q9, q10 - sse
@@ -212,6 +216,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {d8-d15}
     pop             {pc}
     ENDP
 
@@ -227,10 +233,11 @@
 ;================================================
 |vp8_variance_halfpixvar16x16_hv_neon| PROC
     push            {lr}
+    vpush           {d8-d15}
 
     vld1.u8         {d0, d1, d2, d3}, [r0], r1      ;load src data
 
-    ldr             lr, [sp, #4]           ;load *sse from stack
+    ldr             lr, [sp, #68]           ;load *sse from stack
     vmov.i8         q13, #0                      ;q8 - sum
     vext.8          q1, q0, q1, #1          ;construct src_ptr[1]
 
@@ -331,6 +338,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {d8-d15}
     pop             {pc}
     ENDP
 
@@ -349,10 +358,11 @@
 
 |vp8_sub_pixel_variance16x16s_neon| PROC
     push            {r4, lr}
+    vpush           {d8-d15}
 
-    ldr             r4, [sp, #8]            ;load *dst_ptr from stack
-    ldr             r12, [sp, #12]          ;load dst_pixels_per_line from stack
-    ldr             lr, [sp, #16]           ;load *sse from stack
+    ldr             r4, [sp, #72]           ;load *dst_ptr from stack
+    ldr             r12, [sp, #76]          ;load dst_pixels_per_line from stack
+    ldr             lr, [sp, #80]           ;load *sse from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             secondpass_bfilter16x16s_only
@@ -566,6 +576,7 @@
     add             sp, sp, #256
     vmov.32         r0, d0[0]                   ;return
 
+    vpop            {d8-d15}
     pop             {r4, pc}
     ENDP
 
diff --git a/vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm b/vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm
index f6b6847..9d9f9e0 100644
--- a/vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm
+++ b/vp8/common/arm/neon/vp8_subpixelvariance8x8_neon.asm
@@ -26,11 +26,12 @@
 
 |vp8_sub_pixel_variance8x8_neon| PROC
     push            {r4-r5, lr}
+    vpush           {d8-d15}
 
     adr             r12, bilinear_taps_coeff
-    ldr             r4, [sp, #12]           ;load *dst_ptr from stack
-    ldr             r5, [sp, #16]           ;load dst_pixels_per_line from stack
-    ldr             lr, [sp, #20]           ;load *sse from stack
+    ldr             r4, [sp, #76]           ;load *dst_ptr from stack
+    ldr             r5, [sp, #80]           ;load dst_pixels_per_line from stack
+    ldr             lr, [sp, #84]           ;load *sse from stack
 
     cmp             r2, #0                  ;skip first_pass filter if xoffset=0
     beq             skip_firstpass_filter
@@ -210,6 +211,8 @@
     vsub.u32        d0, d1, d10
 
     vmov.32         r0, d0[0]                   ;return
+
+    vpop            {d8-d15}
     pop             {r4-r5, pc}
 
     ENDP
diff --git a/vp8/common/common.h b/vp8/common/common.h
index ee5b58c..17262d6 100644
--- a/vp8/common/common.h
+++ b/vp8/common/common.h
@@ -22,6 +22,9 @@
 extern "C" {
 #endif
 
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
 /* Only need this for fixed-size arrays, for structs just assign. */
 
 #define vp8_copy( Dest, Src) { \
diff --git a/vp8/common/x86/recon_sse2.asm b/vp8/common/x86/recon_sse2.asm
index 1434bcd..7141f83 100644
--- a/vp8/common/x86/recon_sse2.asm
+++ b/vp8/common/x86/recon_sse2.asm
@@ -365,6 +365,7 @@
     GET_GOT     rbx
     push        rsi
     push        rdi
+    push        rbx
     ; end prolog
 
     ; read top row
@@ -395,8 +396,11 @@
     movsxd      rcx,        dword ptr arg(1) ;dst_stride
 
 .vp8_intra_pred_uv_tm_%1_loop:
-    movd        xmm3,       [rsi]
-    movd        xmm5,       [rsi+rax]
+    mov         bl,         [rsi]
+    movd        xmm3,       ebx
+
+    mov         bl,         [rsi+rax]
+    movd        xmm5,       ebx
 %ifidn %1, sse2
     punpcklbw   xmm3,       xmm0
     punpcklbw   xmm5,       xmm0
@@ -419,6 +423,7 @@
     jnz .vp8_intra_pred_uv_tm_%1_loop
 
     ; begin epilog
+    pop         rbx
     pop         rdi
     pop         rsi
     RESTORE_GOT
@@ -486,10 +491,8 @@
     SHADOW_ARGS_TO_STACK 5
     push        rsi
     push        rdi
-%ifidn %1, ssse3
-%ifndef GET_GOT_SAVE_ARG
     push        rbx
-%endif
+%ifidn %1, ssse3
     GET_GOT     rbx
 %endif
     ; end prolog
@@ -507,13 +510,16 @@
 %ifidn %1, ssse3
     lea         rdx,        [rcx*3]
     movdqa      xmm2,       [GLOBAL(dc_00001111)]
-    lea         rbx,        [rax*3]
 %endif
 
 %ifidn %1, mmx2
 .vp8_intra_pred_uv_ho_%1_loop:
-    movd        mm0,        [rsi]
-    movd        mm1,        [rsi+rax]
+    mov         bl,         [rsi]
+    movd        mm0,        ebx
+
+    mov         bl,         [rsi+rax]
+    movd        mm1,        ebx
+
     punpcklbw   mm0,        mm0
     punpcklbw   mm1,        mm1
     pshufw      mm0,        mm0, 0x0
@@ -525,10 +531,19 @@
     dec         edx
     jnz .vp8_intra_pred_uv_ho_%1_loop
 %else
-    movd        xmm0,       [rsi]
-    movd        xmm3,       [rsi+rax]
-    movd        xmm1,       [rsi+rax*2]
-    movd        xmm4,       [rsi+rbx]
+    mov         bl,         [rsi]
+    movd        xmm0,       ebx
+
+    mov         bl,         [rsi+rax]
+    movd        xmm3,       ebx
+
+    mov         bl,         [rsi+rax*2]
+    movd        xmm1,       ebx
+
+    lea         rbx,        [rax*3]
+    mov         bl,         [rsi+rbx]
+    movd        xmm4,       ebx
+
     punpcklbw   xmm0,       xmm3
     punpcklbw   xmm1,       xmm4
     pshufb      xmm0,       xmm2
@@ -539,10 +554,20 @@
     movhps [rdi+rdx],       xmm1
     lea         rsi,        [rsi+rax*4]
     lea         rdi,        [rdi+rcx*4]
-    movd        xmm0,       [rsi]
-    movd        xmm3,       [rsi+rax]
-    movd        xmm1,       [rsi+rax*2]
-    movd        xmm4,       [rsi+rbx]
+
+    mov         bl,         [rsi]
+    movd        xmm0,       ebx
+
+    mov         bl,         [rsi+rax]
+    movd        xmm3,       ebx
+
+    mov         bl,         [rsi+rax*2]
+    movd        xmm1,       ebx
+
+    lea         rbx,        [rax*3]
+    mov         bl,         [rsi+rbx]
+    movd        xmm4,       ebx
+
     punpcklbw   xmm0,       xmm3
     punpcklbw   xmm1,       xmm4
     pshufb      xmm0,       xmm2
@@ -556,10 +581,8 @@
     ; begin epilog
 %ifidn %1, ssse3
     RESTORE_GOT
-%ifndef GET_GOT_SAVE_ARG
+%endif
     pop         rbx
-%endif
-%endif
     pop         rdi
     pop         rsi
     UNSHADOW_ARGS
@@ -893,6 +916,7 @@
     SAVE_XMM 7
     push        rsi
     push        rdi
+    push        rbx
     GET_GOT     rbx
     ; end prolog
 
@@ -926,8 +950,11 @@
     mov         rdi,        arg(0) ;dst;
     movsxd      rcx,        dword ptr arg(1) ;dst_stride
 vp8_intra_pred_y_tm_%1_loop:
-    movd        xmm4,       [rsi]
-    movd        xmm5,       [rsi+rax]
+    mov         bl,         [rsi]
+    movd        xmm4,       ebx
+
+    mov         bl,         [rsi+rax]
+    movd        xmm5,       ebx
 %ifidn %1, sse2
     punpcklbw   xmm4,       xmm0
     punpcklbw   xmm5,       xmm0
@@ -956,6 +983,7 @@
 
     ; begin epilog
     RESTORE_GOT
+    pop         rbx
     pop         rdi
     pop         rsi
     RESTORE_XMM
@@ -1029,6 +1057,7 @@
     SHADOW_ARGS_TO_STACK 5
     push        rsi
     push        rdi
+    push        rbx
     ; end prolog
 
     ;arg(2) not used
@@ -1041,8 +1070,11 @@
     movsxd      rcx,        dword ptr arg(1) ;dst_stride
 
 vp8_intra_pred_y_ho_sse2_loop:
-    movd        xmm0,       [rsi]
-    movd        xmm1,       [rsi+rax]
+    mov         bl,         [rsi]
+    movd        xmm0,       ebx
+    mov         bl,         [rsi+rax]
+    movd        xmm1,       ebx
+
     ; FIXME use pshufb for ssse3 version
     punpcklbw   xmm0,       xmm0
     punpcklbw   xmm1,       xmm1
@@ -1058,6 +1090,7 @@
     jnz vp8_intra_pred_y_ho_sse2_loop
 
     ; begin epilog
+    pop         rbx
     pop         rdi
     pop         rsi
     UNSHADOW_ARGS
diff --git a/vp8/decoder/dboolhuff.c b/vp8/decoder/dboolhuff.c
index 0007d7a..b874d4c 100644
--- a/vp8/decoder/dboolhuff.c
+++ b/vp8/decoder/dboolhuff.c
@@ -10,11 +10,12 @@
 
 
 #include "dboolhuff.h"
+#include "vp8/common/common.h"
 
 int vp8dx_start_decode(BOOL_DECODER *br,
                        const unsigned char *source,
                        unsigned int source_sz,
-                       vp8_decrypt_cb *decrypt_cb,
+                       vpx_decrypt_cb decrypt_cb,
                        void *decrypt_state)
 {
     br->user_buffer_end = source+source_sz;
@@ -39,7 +40,7 @@
     const unsigned char *bufptr = br->user_buffer;
     VP8_BD_VALUE value = br->value;
     int count = br->count;
-    int shift = VP8_BD_VALUE_SIZE - 8 - (count + 8);
+    int shift = VP8_BD_VALUE_SIZE - CHAR_BIT - (count + CHAR_BIT);
     size_t bytes_left = br->user_buffer_end - bufptr;
     size_t bits_left = bytes_left * CHAR_BIT;
     int x = (int)(shift + CHAR_BIT - bits_left);
@@ -47,7 +48,7 @@
     unsigned char decrypted[sizeof(VP8_BD_VALUE) + 1];
 
     if (br->decrypt_cb) {
-        size_t n = bytes_left > sizeof(decrypted) ? sizeof(decrypted) : bytes_left;
+        size_t n = MIN(sizeof(decrypted), bytes_left);
         br->decrypt_cb(br->decrypt_state, bufptr, decrypted, (int)n);
         bufptr = decrypted;
     }
diff --git a/vp8/decoder/dboolhuff.h b/vp8/decoder/dboolhuff.h
index 36af7ee..51c5adc 100644
--- a/vp8/decoder/dboolhuff.h
+++ b/vp8/decoder/dboolhuff.h
@@ -17,6 +17,7 @@
 
 #include "vpx_config.h"
 #include "vpx_ports/mem.h"
+#include "vpx/vp8dx.h"
 #include "vpx/vpx_integer.h"
 
 #ifdef __cplusplus
@@ -32,12 +33,6 @@
   Even relatively modest values like 100 would work fine.*/
 #define VP8_LOTS_OF_BITS (0x40000000)
 
-/*Decrypt n bytes of data from input -> output, using the decrypt_state
-   passed in VP8D_SET_DECRYPTOR.
-*/
-typedef void (vp8_decrypt_cb)(void *decrypt_state, const unsigned char *input,
-                              unsigned char *output, int count);
-
 typedef struct
 {
     const unsigned char *user_buffer_end;
@@ -45,7 +40,7 @@
     VP8_BD_VALUE         value;
     int                  count;
     unsigned int         range;
-    vp8_decrypt_cb      *decrypt_cb;
+    vpx_decrypt_cb       decrypt_cb;
     void                *decrypt_state;
 } BOOL_DECODER;
 
@@ -54,7 +49,7 @@
 int vp8dx_start_decode(BOOL_DECODER *br,
                        const unsigned char *source,
                        unsigned int source_sz,
-                       vp8_decrypt_cb *decrypt_cb,
+                       vpx_decrypt_cb decrypt_cb,
                        void *decrypt_state);
 
 void vp8dx_bool_decoder_fill(BOOL_DECODER *br);
diff --git a/vp8/decoder/decodeframe.c b/vp8/decoder/decodeframe.c
index bfde599..e7cf0d9 100644
--- a/vp8/decoder/decodeframe.c
+++ b/vp8/decoder/decodeframe.c
@@ -17,6 +17,7 @@
 #include "vp8/common/reconintra4x4.h"
 #include "vp8/common/reconinter.h"
 #include "detokenize.h"
+#include "vp8/common/common.h"
 #include "vp8/common/invtrans.h"
 #include "vp8/common/alloccommon.h"
 #include "vp8/common/entropymode.h"
@@ -631,9 +632,17 @@
             xd->dst.u_buffer = dst_buffer[1] + recon_uvoffset;
             xd->dst.v_buffer = dst_buffer[2] + recon_uvoffset;
 
-            xd->pre.y_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][0] + recon_yoffset;
-            xd->pre.u_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][1] + recon_uvoffset;
-            xd->pre.v_buffer = ref_buffer[xd->mode_info_context->mbmi.ref_frame][2] + recon_uvoffset;
+            if (xd->mode_info_context->mbmi.ref_frame >= LAST_FRAME) {
+              MV_REFERENCE_FRAME ref = xd->mode_info_context->mbmi.ref_frame;
+              xd->pre.y_buffer = ref_buffer[ref][0] + recon_yoffset;
+              xd->pre.u_buffer = ref_buffer[ref][1] + recon_uvoffset;
+              xd->pre.v_buffer = ref_buffer[ref][2] + recon_uvoffset;
+            } else {
+              // ref_frame is INTRA_FRAME, pre buffer should not be used.
+              xd->pre.y_buffer = 0;
+              xd->pre.u_buffer = 0;
+              xd->pre.v_buffer = 0;
+            }
 
             /* propagate errors from reference frames */
             xd->corrupted |= ref_fb_corrupted[xd->mode_info_context->mbmi.ref_frame];
@@ -1010,8 +1019,7 @@
         const unsigned char *clear = data;
         if (pbi->decrypt_cb)
         {
-            int n = (int)(data_end - data);
-            if (n > 10) n = 10;
+            int n = (int)MIN(sizeof(clear_buffer), data_end - data);
             pbi->decrypt_cb(pbi->decrypt_state, data, clear_buffer, n);
             clear = clear_buffer;
         }
diff --git a/vp8/decoder/error_concealment.c b/vp8/decoder/error_concealment.c
index 0b58c98..4b304c8 100644
--- a/vp8/decoder/error_concealment.c
+++ b/vp8/decoder/error_concealment.c
@@ -15,9 +15,7 @@
 #include "decodemv.h"
 #include "vpx_mem/vpx_mem.h"
 #include "vp8/common/findnearmv.h"
-
-#define MIN(x,y) (((x)<(y))?(x):(y))
-#define MAX(x,y) (((x)>(y))?(x):(y))
+#include "vp8/common/common.h"
 
 #define FLOOR(x,q) ((x) & -(1 << (q)))
 
diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c
index 2d9e343..29fea61 100644
--- a/vp8/decoder/onyxd_if.c
+++ b/vp8/decoder/onyxd_if.c
@@ -178,12 +178,6 @@
    return pbi->common.error.error_code;
 }
 
-/*For ARM NEON, d8-d15 are callee-saved registers, and need to be saved by us.*/
-#if HAVE_NEON
-extern void vp8_push_neon(int64_t *store);
-extern void vp8_pop_neon(int64_t *store);
-#endif
-
 static int get_free_fb (VP8_COMMON *cm)
 {
     int i;
@@ -307,9 +301,6 @@
                                   const uint8_t *source,
                                   int64_t time_stamp)
 {
-#if HAVE_NEON
-    int64_t dx_store_reg[8];
-#endif
     VP8_COMMON *cm = &pbi->common;
     int retcode = -1;
 
@@ -319,15 +310,6 @@
     if(retcode <= 0)
         return retcode;
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_push_neon(dx_store_reg);
-    }
-#endif
-
     cm->new_fb_idx = get_free_fb (cm);
 
     /* setup reference frames for vp8_decode_frame */
@@ -403,15 +385,6 @@
     pbi->last_time_stamp = time_stamp;
 
 decode_exit:
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_pop_neon(dx_store_reg);
-    }
-#endif
-
     pbi->common.error.setjmp = 0;
     return retcode;
 }
diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h
index 8ef4894..aa2cc57 100644
--- a/vp8/decoder/onyxd_int.h
+++ b/vp8/decoder/onyxd_int.h
@@ -126,7 +126,7 @@
     int independent_partitions;
     int frame_corrupt_residual;
 
-    vp8_decrypt_cb *decrypt_cb;
+    vpx_decrypt_cb decrypt_cb;
     void *decrypt_state;
 } VP8D_COMP;
 
diff --git a/vp8/encoder/arm/neon/subtract_neon.asm b/vp8/encoder/arm/neon/subtract_neon.asm
index 5bda786..840cb33 100644
--- a/vp8/encoder/arm/neon/subtract_neon.asm
+++ b/vp8/encoder/arm/neon/subtract_neon.asm
@@ -65,8 +65,10 @@
 ;                           unsigned char *pred, int pred_stride)
 |vp8_subtract_mby_neon| PROC
     push            {r4-r7}
+    vpush           {d8-d15}
+
     mov             r12, #4
-    ldr             r4, [sp, #16]           ; pred_stride
+    ldr             r4, [sp, #80]           ; pred_stride
     mov             r6, #32                 ; "diff" stride x2
     add             r5, r0, #16             ; second diff pointer
 
@@ -101,6 +103,7 @@
     subs            r12, r12, #1
     bne             subtract_mby_loop
 
+    vpop            {d8-d15}
     pop             {r4-r7}
     bx              lr
     ENDP
@@ -112,9 +115,11 @@
 
 |vp8_subtract_mbuv_neon| PROC
     push            {r4-r7}
-    ldr             r4, [sp, #16]       ; upred
-    ldr             r5, [sp, #20]       ; vpred
-    ldr             r6, [sp, #24]       ; pred_stride
+    vpush           {d8-d15}
+
+    ldr             r4, [sp, #80]       ; upred
+    ldr             r5, [sp, #84]       ; vpred
+    ldr             r6, [sp, #88]       ; pred_stride
     add             r0, r0, #512        ; short *udiff = diff + 256;
     mov             r12, #32            ; "diff" stride x2
     add             r7, r0, #16         ; second diff pointer
@@ -191,6 +196,7 @@
     vst1.16         {q14}, [r0], r12
     vst1.16         {q15}, [r7], r12
 
+    vpop            {d8-d15}
     pop             {r4-r7}
     bx              lr
 
diff --git a/vp8/encoder/arm/neon/vp8_memcpy_neon.asm b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm
index 5b9f11e..d219e2d 100644
--- a/vp8/encoder/arm/neon/vp8_memcpy_neon.asm
+++ b/vp8/encoder/arm/neon/vp8_memcpy_neon.asm
@@ -21,6 +21,7 @@
 ;void vp8_memcpy_partial_neon(unsigned char *dst_ptr, unsigned char *src_ptr,
 ;                             int sz);
 |vp8_memcpy_partial_neon| PROC
+    vpush               {d8-d15}
     ;pld                [r1]                        ;preload pred data
     ;pld                [r1, #128]
     ;pld                [r1, #256]
@@ -64,6 +65,7 @@
     bne             extra_copy_neon_loop
 
 done_copy_neon_loop
+    vpop            {d8-d15}
     bx              lr
     ENDP
 
diff --git a/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm
index 55edbf5..f82af3e 100644
--- a/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm
+++ b/vp8/encoder/arm/neon/vp8_mse16x16_neon.asm
@@ -27,6 +27,8 @@
 ;from vp8_variance().
 
 |vp8_mse16x16_neon| PROC
+    vpush           {q7}
+
     vmov.i8         q7, #0                      ;q7, q8, q9, q10 - sse
     vmov.i8         q8, #0
     vmov.i8         q9, #0
@@ -62,7 +64,7 @@
     vadd.u32        q7, q7, q8
     vadd.u32        q9, q9, q10
 
-    ldr             r12, [sp]               ;load *sse from stack
+    ldr             r12, [sp, #16]              ;load *sse from stack
 
     vadd.u32        q10, q7, q9
     vpaddl.u32      q1, q10
@@ -71,6 +73,7 @@
     vst1.32         {d0[0]}, [r12]
     vmov.32         r0, d0[0]
 
+    vpop            {q7}
     bx              lr
 
     ENDP
@@ -82,6 +85,8 @@
 ; r2    unsigned char *ref_ptr,
 ; r3    int  recon_stride
 |vp8_get4x4sse_cs_neon| PROC
+    vpush           {q7}
+
     vld1.8          {d0}, [r0], r1              ;Load up source and reference
     vld1.8          {d4}, [r2], r3
     vld1.8          {d1}, [r0], r1
@@ -109,6 +114,8 @@
     vadd.u64        d0, d2, d3
 
     vmov.32         r0, d0[0]
+
+    vpop            {q7}
     bx              lr
 
     ENDP
diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c
index 0b11ea6..54abe76 100644
--- a/vp8/encoder/mcomp.c
+++ b/vp8/encoder/mcomp.c
@@ -17,6 +17,7 @@
 #include <limits.h>
 #include <math.h>
 #include "vp8/common/findnearmv.h"
+#include "vp8/common/common.h"
 
 #ifdef VP8_ENTROPY_STATS
 static int mv_ref_ct [31] [4] [2];
diff --git a/vp8/encoder/mr_dissim.c b/vp8/encoder/mr_dissim.c
index 71218cc..8d96445 100644
--- a/vp8/encoder/mr_dissim.c
+++ b/vp8/encoder/mr_dissim.c
@@ -15,6 +15,7 @@
 #include "mr_dissim.h"
 #include "vpx_mem/vpx_mem.h"
 #include "rdopt.h"
+#include "vp8/common/common.h"
 
 void vp8_cal_low_res_mb_cols(VP8_COMP *cpi)
 {
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index ef37c0e..560134e 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -1761,8 +1761,11 @@
 
 }
 
+#ifndef M_LOG2_E
 #define M_LOG2_E 0.693147180559945309417
+#endif
 #define log2f(x) (log (x) / (float) M_LOG2_E)
+
 static void cal_mvsadcosts(int *mvsadcost[2])
 {
     int i = 1;
@@ -4817,33 +4820,11 @@
 }
 #endif
 
-/* For ARM NEON, d8-d15 are callee-saved registers, and need to be saved. */
-#if HAVE_NEON
-extern void vp8_push_neon(int64_t *store);
-extern void vp8_pop_neon(int64_t *store);
-#endif
-
-
 int vp8_receive_raw_frame(VP8_COMP *cpi, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time)
 {
-#if HAVE_NEON
-    int64_t store_reg[8];
-#if CONFIG_RUNTIME_CPU_DETECT
-    VP8_COMMON            *cm = &cpi->common;
-#endif
-#endif
     struct vpx_usec_timer  timer;
     int                    res = 0;
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_push_neon(store_reg);
-    }
-#endif
-
     vpx_usec_timer_start(&timer);
 
     /* Reinit the lookahead buffer if the frame size changes */
@@ -4860,15 +4841,6 @@
     vpx_usec_timer_mark(&timer);
     cpi->time_receive_data += vpx_usec_timer_elapsed(&timer);
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_pop_neon(store_reg);
-    }
-#endif
-
     return res;
 }
 
@@ -4889,9 +4861,6 @@
 
 int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned long *size, unsigned char *dest, unsigned char *dest_end, int64_t *time_stamp, int64_t *time_end, int flush)
 {
-#if HAVE_NEON
-    int64_t store_reg[8];
-#endif
     VP8_COMMON *cm;
     struct vpx_usec_timer  tsctimer;
     struct vpx_usec_timer  ticktimer;
@@ -4911,15 +4880,6 @@
 
     cpi->common.error.setjmp = 1;
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_push_neon(store_reg);
-    }
-#endif
-
     vpx_usec_timer_start(&cmptimer);
 
     cpi->source = NULL;
@@ -5002,14 +4962,6 @@
 
 #endif
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-        if (cm->cpu_caps & HAS_NEON)
-#endif
-        {
-            vp8_pop_neon(store_reg);
-        }
-#endif
         return -1;
     }
 
@@ -5413,15 +5365,6 @@
 #endif
 #endif
 
-#if HAVE_NEON
-#if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->cpu_caps & HAS_NEON)
-#endif
-    {
-        vp8_pop_neon(store_reg);
-    }
-#endif
-
     cpi->common.error.setjmp = 0;
 
     return 0;
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h
index 6b37167..df17dff 100644
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -61,9 +61,6 @@
 #define VP8_TEMPORAL_ALT_REF 1
 #endif
 
-#define MAX(x,y) (((x)>(y))?(x):(y))
-#define MIN(x,y) (((x)<(y))?(x):(y))
-
 typedef struct
 {
     int kf_indicated;
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index c5279fe..39a3baf 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -14,6 +14,7 @@
 #include "onyx_int.h"
 #include "modecosts.h"
 #include "encodeintra.h"
+#include "vp8/common/common.h"
 #include "vp8/common/entropymode.h"
 #include "pickinter.h"
 #include "vp8/common/findnearmv.h"
diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk
index dfb54a5..cdb2716 100644
--- a/vp8/vp8_common.mk
+++ b/vp8/vp8_common.mk
@@ -172,8 +172,6 @@
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/sixtappredict8x8_neon$(ASM)
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/sixtappredict16x16_neon$(ASM)
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/buildintrapredictorsmby_neon$(ASM)
-VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/save_reg_neon$(ASM)
-VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/idct_dequant_full_2x_neon$(ASM)
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/idct_dequant_0_2x_neon$(ASM)
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/idct_blk_neon.c
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/variance_neon$(ASM)
@@ -187,6 +185,7 @@
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/dc_only_idct_add_neon.c
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/dequant_idct_neon.c
 VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/dequantizeb_neon.c
+VP8_COMMON_SRCS-$(HAVE_NEON)  += common/arm/neon/idct_dequant_full_2x_neon.c
 
 
 $(eval $(call rtcd_h_template,vp8_rtcd,vp8/common/rtcd_defs.pl))
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index 4c896b1..6ca6087 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -1235,6 +1235,8 @@
 
         0,                  /* rc_dropframe_thresh */
         0,                  /* rc_resize_allowed */
+        1,                  /* rc_scaled_width */
+        1,                  /* rc_scaled_height */
         60,                 /* rc_resize_down_thresold */
         30,                 /* rc_resize_up_thresold */
 
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c
index 0b4c4cb..10cbc6a 100644
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -16,9 +16,10 @@
 #include "vpx/vp8dx.h"
 #include "vpx/internal/vpx_codec_internal.h"
 #include "vpx_version.h"
+#include "common/alloccommon.h"
+#include "common/common.h"
 #include "common/onyxd.h"
 #include "decoder/onyxd_int.h"
-#include "common/alloccommon.h"
 #include "vpx_mem/vpx_mem.h"
 #if CONFIG_ERROR_CONCEALMENT
 #include "decoder/error_concealment.h"
@@ -41,19 +42,11 @@
 
 static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t);
 
-static const mem_req_t vp8_mem_req_segs[] =
-{
-    {VP8_SEG_ALG_PRIV,    0, 8, VPX_CODEC_MEM_ZERO, vp8_priv_sz},
-    {VP8_SEG_MAX, 0, 0, 0, NULL}
-};
-
 struct vpx_codec_alg_priv
 {
     vpx_codec_priv_t        base;
-    vpx_codec_mmap_t        mmaps[NELEMENTS(vp8_mem_req_segs)-1];
     vpx_codec_dec_cfg_t     cfg;
     vp8_stream_info_t       si;
-    int                     defer_alloc;
     int                     decoder_init;
     int                     postproc_cfg_set;
     vp8_postproc_cfg_t      postproc_cfg;
@@ -64,7 +57,7 @@
     int                     dbg_color_b_modes_flag;
     int                     dbg_display_mv_flag;
 #endif
-    vp8_decrypt_cb          *decrypt_cb;
+    vpx_decrypt_cb          decrypt_cb;
     void                    *decrypt_state;
     vpx_image_t             img;
     int                     img_setup;
@@ -84,19 +77,14 @@
     return sizeof(vpx_codec_alg_priv_t);
 }
 
-static void vp8_init_ctx(vpx_codec_ctx_t *ctx, const vpx_codec_mmap_t *mmap)
+static void vp8_init_ctx(vpx_codec_ctx_t *ctx)
 {
-    int i;
-
-    ctx->priv = mmap->base;
+    ctx->priv =
+        (vpx_codec_priv_t *)vpx_memalign(8, sizeof(vpx_codec_alg_priv_t));
+    vpx_memset(ctx->priv, 0, sizeof(vpx_codec_alg_priv_t));
     ctx->priv->sz = sizeof(*ctx->priv);
     ctx->priv->iface = ctx->iface;
-    ctx->priv->alg_priv = mmap->base;
-
-    for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
-        ctx->priv->alg_priv->mmaps[i].id = vp8_mem_req_segs[i].id;
-
-    ctx->priv->alg_priv->mmaps[0] = *mmap;
+    ctx->priv->alg_priv = (vpx_codec_alg_priv_t *)ctx->priv;
     ctx->priv->alg_priv->si.sz = sizeof(ctx->priv->alg_priv->si);
     ctx->priv->alg_priv->decrypt_cb = NULL;
     ctx->priv->alg_priv->decrypt_state = NULL;
@@ -110,11 +98,6 @@
     }
 }
 
-static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx)
-{
-    /* nothing to clean up */
-}
-
 static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx,
                                 vpx_codec_priv_enc_mr_cfg_t *data)
 {
@@ -129,17 +112,7 @@
      */
     if (!ctx->priv)
     {
-        vpx_codec_mmap_t mmap;
-
-        mmap.id = vp8_mem_req_segs[0].id;
-        mmap.sz = sizeof(vpx_codec_alg_priv_t);
-        mmap.align = vp8_mem_req_segs[0].align;
-        mmap.flags = vp8_mem_req_segs[0].flags;
-
-        res = vpx_mmap_alloc(&mmap);
-        if (res != VPX_CODEC_OK) return res;
-
-        vp8_init_ctx(ctx, &mmap);
+        vp8_init_ctx(ctx);
 
         /* initialize number of fragments to zero */
         ctx->priv->alg_priv->fragments.count = 0;
@@ -148,7 +121,6 @@
                 (ctx->priv->alg_priv->base.init_flags &
                     VPX_CODEC_USE_INPUT_FRAGMENTS);
 
-        ctx->priv->alg_priv->defer_alloc = 1;
         /*post processing level initialized to do nothing */
     }
 
@@ -175,15 +147,9 @@
 
 static vpx_codec_err_t vp8_destroy(vpx_codec_alg_priv_t *ctx)
 {
-    int i;
-
     vp8_remove_decoder_instances(&ctx->yv12_frame_buffers);
 
-    for (i = NELEMENTS(ctx->mmaps) - 1; i >= 0; i--)
-    {
-        if (ctx->mmaps[i].dtor)
-            ctx->mmaps[i].dtor(&ctx->mmaps[i]);
-    }
+    vpx_free(ctx);
 
     return VPX_CODEC_OK;
 }
@@ -191,7 +157,7 @@
 static vpx_codec_err_t vp8_peek_si_internal(const uint8_t *data,
                                             unsigned int data_sz,
                                             vpx_codec_stream_info_t *si,
-                                            vp8_decrypt_cb *decrypt_cb,
+                                            vpx_decrypt_cb decrypt_cb,
                                             void *decrypt_state)
 {
     vpx_codec_err_t res = VPX_CODEC_OK;
@@ -212,7 +178,7 @@
         const uint8_t *clear = data;
         if (decrypt_cb)
         {
-            int n = data_sz > 10 ? 10 : data_sz;
+            int n = MIN(sizeof(clear_buffer), data_sz);
             decrypt_cb(decrypt_state, data, clear_buffer, n);
             clear = clear_buffer;
         }
@@ -389,74 +355,40 @@
     if ((ctx->si.h != h) || (ctx->si.w != w))
         resolution_change = 1;
 
-    /* Perform deferred allocations, if required */
-    if (!res && ctx->defer_alloc)
-    {
-        int i;
-
-        for (i = 1; !res && i < NELEMENTS(ctx->mmaps); i++)
-        {
-            vpx_codec_dec_cfg_t cfg;
-
-            cfg.w = ctx->si.w;
-            cfg.h = ctx->si.h;
-            ctx->mmaps[i].id = vp8_mem_req_segs[i].id;
-            ctx->mmaps[i].sz = vp8_mem_req_segs[i].sz;
-            ctx->mmaps[i].align = vp8_mem_req_segs[i].align;
-            ctx->mmaps[i].flags = vp8_mem_req_segs[i].flags;
-
-            if (!ctx->mmaps[i].sz)
-                ctx->mmaps[i].sz = vp8_mem_req_segs[i].calc_sz(&cfg,
-                                   ctx->base.init_flags);
-
-            res = vpx_mmap_alloc(&ctx->mmaps[i]);
-        }
-
-        if (!res)
-            vp8_finalize_mmaps(ctx);
-
-        ctx->defer_alloc = 0;
-    }
-
     /* Initialize the decoder instance on the first frame*/
     if (!res && !ctx->decoder_init)
     {
-        res = vpx_validate_mmaps(&ctx->si, ctx->mmaps,
-                                 vp8_mem_req_segs, NELEMENTS(vp8_mem_req_segs),
-                                 ctx->base.init_flags);
+      VP8D_CONFIG oxcf;
 
-        if (!res)
-        {
-            VP8D_CONFIG oxcf;
+      oxcf.Width = ctx->si.w;
+      oxcf.Height = ctx->si.h;
+      oxcf.Version = 9;
+      oxcf.postprocess = 0;
+      oxcf.max_threads = ctx->cfg.threads;
+      oxcf.error_concealment =
+          (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT);
 
-            oxcf.Width = ctx->si.w;
-            oxcf.Height = ctx->si.h;
-            oxcf.Version = 9;
-            oxcf.postprocess = 0;
-            oxcf.max_threads = ctx->cfg.threads;
-            oxcf.error_concealment =
-                    (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT);
+      /* If postprocessing was enabled by the application and a
+       * configuration has not been provided, default it.
+       */
+       if (!ctx->postproc_cfg_set
+           && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC)) {
+         ctx->postproc_cfg.post_proc_flag =
+             VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE;
+         ctx->postproc_cfg.deblocking_level = 4;
+         ctx->postproc_cfg.noise_level = 0;
+       }
 
-            /* If postprocessing was enabled by the application and a
-             * configuration has not been provided, default it.
-             */
-            if (!ctx->postproc_cfg_set
-                && (ctx->base.init_flags & VPX_CODEC_USE_POSTPROC))
-            {
-                ctx->postproc_cfg.post_proc_flag =
-                    VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE;
-                ctx->postproc_cfg.deblocking_level = 4;
-                ctx->postproc_cfg.noise_level = 0;
-            }
-
-            res = vp8_create_decoder_instances(&ctx->yv12_frame_buffers, &oxcf);
-            ctx->yv12_frame_buffers.pbi[0]->decrypt_cb = ctx->decrypt_cb;
-            ctx->yv12_frame_buffers.pbi[0]->decrypt_state = ctx->decrypt_state;
-        }
-
-        ctx->decoder_init = 1;
+       res = vp8_create_decoder_instances(&ctx->yv12_frame_buffers, &oxcf);
+       ctx->decoder_init = 1;
     }
 
+    /* Set these even if already initialized.  The caller may have changed the
+     * decrypt config between frames.
+     */
+    ctx->yv12_frame_buffers.pbi[0]->decrypt_cb = ctx->decrypt_cb;
+    ctx->yv12_frame_buffers.pbi[0]->decrypt_state = ctx->decrypt_state;
+
     if (!res)
     {
         VP8D_COMP *pbi = ctx->yv12_frame_buffers.pbi[0];
@@ -618,89 +550,6 @@
     return img;
 }
 
-
-static
-vpx_codec_err_t vp8_xma_get_mmap(const vpx_codec_ctx_t      *ctx,
-                                 vpx_codec_mmap_t           *mmap,
-                                 vpx_codec_iter_t           *iter)
-{
-    vpx_codec_err_t     res;
-    const mem_req_t  *seg_iter = *iter;
-
-    /* Get address of next segment request */
-    do
-    {
-        if (!seg_iter)
-            seg_iter = vp8_mem_req_segs;
-        else if (seg_iter->id != VP8_SEG_MAX)
-            seg_iter++;
-
-        *iter = (vpx_codec_iter_t)seg_iter;
-
-        if (seg_iter->id != VP8_SEG_MAX)
-        {
-            mmap->id = seg_iter->id;
-            mmap->sz = seg_iter->sz;
-            mmap->align = seg_iter->align;
-            mmap->flags = seg_iter->flags;
-
-            if (!seg_iter->sz)
-                mmap->sz = seg_iter->calc_sz(ctx->config.dec, ctx->init_flags);
-
-            res = VPX_CODEC_OK;
-        }
-        else
-            res = VPX_CODEC_LIST_END;
-    }
-    while (!mmap->sz && res != VPX_CODEC_LIST_END);
-
-    return res;
-}
-
-static vpx_codec_err_t vp8_xma_set_mmap(vpx_codec_ctx_t         *ctx,
-                                        const vpx_codec_mmap_t  *mmap)
-{
-    vpx_codec_err_t res = VPX_CODEC_MEM_ERROR;
-    int i, done;
-
-    if (!ctx->priv)
-    {
-        if (mmap->id == VP8_SEG_ALG_PRIV)
-        {
-            if (!ctx->priv)
-            {
-                vp8_init_ctx(ctx, mmap);
-                res = VPX_CODEC_OK;
-            }
-        }
-    }
-
-    done = 1;
-
-    if (!res && ctx->priv->alg_priv)
-    {
-        for (i = 0; i < NELEMENTS(ctx->priv->alg_priv->mmaps); i++)
-        {
-            if (ctx->priv->alg_priv->mmaps[i].id == mmap->id)
-                if (!ctx->priv->alg_priv->mmaps[i].base)
-                {
-                    ctx->priv->alg_priv->mmaps[i] = *mmap;
-                    res = VPX_CODEC_OK;
-                }
-
-            done &= (ctx->priv->alg_priv->mmaps[i].base != NULL);
-        }
-    }
-
-    if (done && !res)
-    {
-        vp8_finalize_mmaps(ctx->priv->alg_priv);
-        res = ctx->iface->init(ctx, NULL);
-    }
-
-    return res;
-}
-
 static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
                                        YV12_BUFFER_CONFIG  *yv12)
 {
@@ -877,7 +726,7 @@
                                          int ctrl_id,
                                          va_list args)
 {
-    vp8_decrypt_init *init = va_arg(args, vp8_decrypt_init *);
+    vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
 
     if (init)
     {
@@ -904,7 +753,7 @@
     {VP8D_GET_LAST_REF_UPDATES,     vp8_get_last_ref_updates},
     {VP8D_GET_FRAME_CORRUPTED,      vp8_get_frame_corrupted},
     {VP8D_GET_LAST_REF_USED,        vp8_get_last_ref_frame},
-    {VP8D_SET_DECRYPTOR,            vp8_set_decryptor},
+    {VPXD_SET_DECRYPTOR,            vp8_set_decryptor},
     { -1, NULL},
 };
 
@@ -922,8 +771,8 @@
     vp8_init,         /* vpx_codec_init_fn_t       init; */
     vp8_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
     vp8_ctf_maps,     /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
-    vp8_xma_get_mmap, /* vpx_codec_get_mmap_fn_t   get_mmap; */
-    vp8_xma_set_mmap, /* vpx_codec_set_mmap_fn_t   set_mmap; */
+    NOT_IMPLEMENTED,  /* vpx_codec_get_mmap_fn_t   get_mmap; */
+    NOT_IMPLEMENTED,  /* vpx_codec_set_mmap_fn_t   set_mmap; */
     {
         vp8_peek_si,      /* vpx_codec_peek_si_fn_t    peek_si; */
         vp8_get_si,       /* vpx_codec_get_si_fn_t     get_si; */
diff --git a/vp9/common/vp9_blockd.c b/vp9/common/vp9_blockd.c
index fedfb18d..43d6c6e 100644
--- a/vp9/common/vp9_blockd.c
+++ b/vp9/common/vp9_blockd.c
@@ -10,8 +10,8 @@
 
 #include "vp9/common/vp9_blockd.h"
 
-MB_PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
-                                       const MODE_INFO *left_mi, int b) {
+PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
+                                    const MODE_INFO *left_mi, int b) {
   if (b == 0 || b == 2) {
     if (!left_mi || is_inter_block(&left_mi->mbmi))
       return DC_PRED;
@@ -23,8 +23,8 @@
   }
 }
 
-MB_PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
-                                        const MODE_INFO *above_mi, int b) {
+PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
+                                     const MODE_INFO *above_mi, int b) {
   if (b == 0 || b == 1) {
     if (!above_mi || is_inter_block(&above_mi->mbmi))
       return DC_PRED;
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index 55320a6..8ca356d 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -77,9 +77,9 @@
   ZEROMV,
   NEWMV,
   MB_MODE_COUNT
-} MB_PREDICTION_MODE;
+} PREDICTION_MODE;
 
-static INLINE int is_inter_mode(MB_PREDICTION_MODE mode) {
+static INLINE int is_inter_mode(PREDICTION_MODE mode) {
   return mode >= NEARESTMV && mode <= NEWMV;
 }
 
@@ -94,7 +94,7 @@
    is a single probability table. */
 
 typedef struct {
-  MB_PREDICTION_MODE as_mode;
+  PREDICTION_MODE as_mode;
   int_mv as_mv[2];  // first, second inter predictor motion vectors
 } b_mode_info;
 
@@ -122,14 +122,14 @@
 typedef struct {
   // Common for both INTER and INTRA blocks
   BLOCK_SIZE sb_type;
-  MB_PREDICTION_MODE mode;
+  PREDICTION_MODE mode;
   TX_SIZE tx_size;
   uint8_t skip;
   uint8_t segment_id;
   uint8_t seg_id_predicted;  // valid only when temporal_update is enabled
 
   // Only for INTRA blocks
-  MB_PREDICTION_MODE uv_mode;
+  PREDICTION_MODE uv_mode;
 
   // Only for INTER blocks
   MV_REFERENCE_FRAME ref_frame[2];
@@ -144,7 +144,7 @@
   b_mode_info bmi[4];
 } MODE_INFO;
 
-static INLINE MB_PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
+static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
   return mi->mbmi.sb_type < BLOCK_8X8 ? mi->bmi[block].as_mode
                                       : mi->mbmi.mode;
 }
@@ -157,11 +157,11 @@
   return mbmi->ref_frame[1] > INTRA_FRAME;
 }
 
-MB_PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
-                                       const MODE_INFO *left_mi, int b);
+PREDICTION_MODE vp9_left_block_mode(const MODE_INFO *cur_mi,
+                                    const MODE_INFO *left_mi, int b);
 
-MB_PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
-                                        const MODE_INFO *above_mi, int b);
+PREDICTION_MODE vp9_above_block_mode(const MODE_INFO *cur_mi,
+                                     const MODE_INFO *above_mi, int b);
 
 enum mv_precision {
   MV_PRECISION_Q3,
diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h
index 6788eb6..3dc98a8 100644
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -180,7 +180,7 @@
   if (is_inter_block(&mi->mbmi) || type != PLANE_TYPE_Y || xd->lossless) {
     return &vp9_default_scan_orders[tx_size];
   } else {
-    const MB_PREDICTION_MODE mode = get_y_mode(mi, block_idx);
+    const PREDICTION_MODE mode = get_y_mode(mi, block_idx);
     return &vp9_scan_orders[tx_size][intra_mode_to_tx_type_lookup[mode]];
   }
 }
diff --git a/vp9/common/vp9_entropymode.h b/vp9/common/vp9_entropymode.h
index c7b1911..533757b 100644
--- a/vp9/common/vp9_entropymode.h
+++ b/vp9/common/vp9_entropymode.h
@@ -101,8 +101,8 @@
                                                const MODE_INFO *above_mi,
                                                const MODE_INFO *left_mi,
                                                int block) {
-  const MB_PREDICTION_MODE above = vp9_above_block_mode(mi, above_mi, block);
-  const MB_PREDICTION_MODE left = vp9_left_block_mode(mi, left_mi, block);
+  const PREDICTION_MODE above = vp9_above_block_mode(mi, above_mi, block);
+  const PREDICTION_MODE left = vp9_left_block_mode(mi, left_mi, block);
   return vp9_kf_y_mode_prob[above][left];
 }
 
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index 77f563f..20de434 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -120,7 +120,6 @@
   // frame header, 3 reset all contexts.
   int reset_frame_context;
 
-  int frame_flags;
   // MBs, mb_rows/cols is in 16-pixel units; mi_rows/cols is in
   // MODE_INFO (8-pixel) units.
   int MBs;
diff --git a/vp9/common/vp9_postproc.c b/vp9/common/vp9_postproc.c
index 7baa9ee..5601a93 100644
--- a/vp9/common/vp9_postproc.c
+++ b/vp9/common/vp9_postproc.c
@@ -34,7 +34,7 @@
 
 /* global constants */
 #if 0 && CONFIG_POSTPROC_VISUALIZER
-static const unsigned char MB_PREDICTION_MODE_colors[MB_MODE_COUNT][3] = {
+static const unsigned char PREDICTION_MODE_colors[MB_MODE_COUNT][3] = {
   { RGB_TO_YUV(0x98FB98) },   /* PaleGreen */
   { RGB_TO_YUV(0x00FF00) },   /* Green */
   { RGB_TO_YUV(0xADFF2F) },   /* GreenYellow */
@@ -911,9 +911,9 @@
             vl += y_stride * 1;
           }
         } else if (ppflags->display_mb_modes_flag & (1 << mi->mbmi.mode)) {
-          Y = MB_PREDICTION_MODE_colors[mi->mbmi.mode][0];
-          U = MB_PREDICTION_MODE_colors[mi->mbmi.mode][1];
-          V = MB_PREDICTION_MODE_colors[mi->mbmi.mode][2];
+          Y = PREDICTION_MODE_colors[mi->mbmi.mode][0];
+          U = PREDICTION_MODE_colors[mi->mbmi.mode][1];
+          V = PREDICTION_MODE_colors[mi->mbmi.mode][2];
 
           vp9_blend_mb_inner(y_ptr + x, u_ptr + (x >> 1), v_ptr + (x >> 1),
                              Y, U, V, 0xc000, y_stride);
diff --git a/vp9/common/vp9_reconintra.c b/vp9/common/vp9_reconintra.c
index 44951b5..32e4551 100644
--- a/vp9/common/vp9_reconintra.c
+++ b/vp9/common/vp9_reconintra.c
@@ -311,7 +311,7 @@
 
 static void build_intra_predictors(const MACROBLOCKD *xd, const uint8_t *ref,
                                    int ref_stride, uint8_t *dst, int dst_stride,
-                                   MB_PREDICTION_MODE mode, TX_SIZE tx_size,
+                                   PREDICTION_MODE mode, TX_SIZE tx_size,
                                    int up_available, int left_available,
                                    int right_available, int x, int y,
                                    int plane) {
@@ -434,7 +434,7 @@
 }
 
 void vp9_predict_intra_block(const MACROBLOCKD *xd, int block_idx, int bwl_in,
-                             TX_SIZE tx_size, MB_PREDICTION_MODE mode,
+                             TX_SIZE tx_size, PREDICTION_MODE mode,
                              const uint8_t *ref, int ref_stride,
                              uint8_t *dst, int dst_stride,
                              int aoff, int loff, int plane) {
diff --git a/vp9/common/vp9_reconintra.h b/vp9/common/vp9_reconintra.h
index abc1767..d09d2a1 100644
--- a/vp9/common/vp9_reconintra.h
+++ b/vp9/common/vp9_reconintra.h
@@ -19,7 +19,7 @@
 #endif
 
 void vp9_predict_intra_block(const MACROBLOCKD *xd, int block_idx, int bwl_in,
-                             TX_SIZE tx_size, MB_PREDICTION_MODE mode,
+                             TX_SIZE tx_size, PREDICTION_MODE mode,
                              const uint8_t *ref, int ref_stride,
                              uint8_t *dst, int dst_stride,
                              int aoff, int loff, int plane);
diff --git a/vp9/common/vp9_rtcd_defs.pl b/vp9/common/vp9_rtcd_defs.pl
index b455592..d4c3065 100644
--- a/vp9/common/vp9_rtcd_defs.pl
+++ b/vp9/common/vp9_rtcd_defs.pl
@@ -12,8 +12,7 @@
 /* Encoder forward decls */
 struct macroblock;
 struct vp9_variance_vtable;
-
-#define DEC_MVCOSTS int *mvjcost, int *mvcost[2]
+struct search_site_config;
 struct mv;
 union int_mv;
 struct yv12_buffer_config;
@@ -564,33 +563,6 @@
 add_proto qw/unsigned int vp9_sad4x4_avg/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int  ref_stride, const uint8_t *second_pred, unsigned int max_sad";
 specialize qw/vp9_sad4x4_avg/, "$sse_x86inc";
 
-add_proto qw/unsigned int vp9_variance_halfpixvar16x16_h/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar16x16_h/, "$sse2_x86inc";
-
-add_proto qw/unsigned int vp9_variance_halfpixvar16x16_v/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar16x16_v/, "$sse2_x86inc";
-
-add_proto qw/unsigned int vp9_variance_halfpixvar16x16_hv/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar16x16_hv/, "$sse2_x86inc";
-
-add_proto qw/unsigned int vp9_variance_halfpixvar64x64_h/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar64x64_h/;
-
-add_proto qw/unsigned int vp9_variance_halfpixvar64x64_v/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar64x64_v/;
-
-add_proto qw/unsigned int vp9_variance_halfpixvar64x64_hv/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar64x64_hv/;
-
-add_proto qw/unsigned int vp9_variance_halfpixvar32x32_h/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar32x32_h/;
-
-add_proto qw/unsigned int vp9_variance_halfpixvar32x32_v/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar32x32_v/;
-
-add_proto qw/unsigned int vp9_variance_halfpixvar32x32_hv/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_variance_halfpixvar32x32_hv/;
-
 add_proto qw/void vp9_sad64x64x3/, "const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int  ref_stride, unsigned int *sad_array";
 specialize qw/vp9_sad64x64x3/;
 
@@ -679,9 +651,6 @@
 add_proto qw/void vp9_sad4x4x4d/, "const uint8_t *src_ptr, int  src_stride, const uint8_t* const ref_ptr[], int  ref_stride, unsigned int *sad_array";
 specialize qw/vp9_sad4x4x4d sse/;
 
-#add_proto qw/unsigned int vp9_sub_pixel_mse16x16/, "const uint8_t *src_ptr, int  src_pixels_per_line, int  xoffset, int  yoffset, const uint8_t *dst_ptr, int dst_pixels_per_line, unsigned int *sse";
-#specialize qw/vp9_sub_pixel_mse16x16 sse2 mmx/;
-
 add_proto qw/unsigned int vp9_mse16x16/, "const uint8_t *src_ptr, int  source_stride, const uint8_t *ref_ptr, int  recon_stride, unsigned int *sse";
 specialize qw/vp9_mse16x16 mmx/, "$sse2_x86inc", "$avx2_x86inc";
 
@@ -694,12 +663,6 @@
 add_proto qw/unsigned int vp9_mse8x8/, "const uint8_t *src_ptr, int  source_stride, const uint8_t *ref_ptr, int  recon_stride, unsigned int *sse";
 specialize qw/vp9_mse8x8/;
 
-add_proto qw/unsigned int vp9_sub_pixel_mse64x64/, "const uint8_t *src_ptr, int  source_stride, int  xoffset, int  yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_sub_pixel_mse64x64/;
-
-add_proto qw/unsigned int vp9_sub_pixel_mse32x32/, "const uint8_t *src_ptr, int  source_stride, int  xoffset, int  yoffset, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse";
-specialize qw/vp9_sub_pixel_mse32x32/;
-
 add_proto qw/unsigned int vp9_get_mb_ss/, "const int16_t *";
 specialize qw/vp9_get_mb_ss mmx sse2/;
 # ENCODEMB INVOKE
@@ -744,7 +707,7 @@
 specialize qw/vp9_fdct4x4 sse2 avx2/;
 
 add_proto qw/void vp9_fdct8x8/, "const int16_t *input, int16_t *output, int stride";
-specialize qw/vp9_fdct8x8 sse2 avx2/;
+specialize qw/vp9_fdct8x8 sse2 avx2/, "$ssse3_x86_64";
 
 add_proto qw/void vp9_fdct16x16/, "const int16_t *input, int16_t *output, int stride";
 specialize qw/vp9_fdct16x16 sse2 avx2/;
@@ -758,20 +721,20 @@
 #
 # Motion search
 #
-add_proto qw/int vp9_full_search_sad/, "const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, DEC_MVCOSTS, const struct mv *center_mv, struct mv *best_mv";
+add_proto qw/int vp9_full_search_sad/, "const struct macroblock *x, const struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv, struct mv *best_mv";
 specialize qw/vp9_full_search_sad sse3 sse4_1/;
 $vp9_full_search_sad_sse3=vp9_full_search_sadx3;
 $vp9_full_search_sad_sse4_1=vp9_full_search_sadx8;
 
-add_proto qw/int vp9_refining_search_sad/, "const struct macroblock *x, struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, DEC_MVCOSTS, const struct mv *center_mv";
+add_proto qw/int vp9_refining_search_sad/, "const struct macroblock *x, struct mv *ref_mv, int sad_per_bit, int distance, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
 specialize qw/vp9_refining_search_sad sse3/;
 $vp9_refining_search_sad_sse3=vp9_refining_search_sadx4;
 
-add_proto qw/int vp9_diamond_search_sad/, "const struct macroblock *x, struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, DEC_MVCOSTS, const struct mv *center_mv";
+add_proto qw/int vp9_diamond_search_sad/, "const struct macroblock *x, const struct search_site_config *cfg,  struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
 specialize qw/vp9_diamond_search_sad sse3/;
 $vp9_diamond_search_sad_sse3=vp9_diamond_search_sadx4;
 
-add_proto qw/int vp9_full_range_search/, "const struct macroblock *x, struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, DEC_MVCOSTS, const struct mv *center_mv";
+add_proto qw/int vp9_full_range_search/, "const struct macroblock *x, const struct search_site_config *cfg, struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
 specialize qw/vp9_full_range_search/;
 
 add_proto qw/void vp9_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_size, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count";
diff --git a/vp9/common/vp9_tapify.py b/vp9/common/vp9_tapify.py
deleted file mode 100644
index 99529cf..0000000
--- a/vp9/common/vp9_tapify.py
+++ /dev/null
@@ -1,106 +0,0 @@
-"""
- *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
-"""
-#!/usr/bin/env python
-import sys,string,os,re,math,numpy
-scale = 2**16
-def dist(p1,p2):
-  x1,y1 = p1
-  x2,y2 = p2
-  if x1==x2 and y1==y2 :
-    return 1.0 
-  return 1/ math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
-
-def gettaps(p):
-  def l(b):
-    return int(math.floor(b))
-  def h(b):
-    return int(math.ceil(b))
-  def t(b,p,s):
-    return int((scale*dist(b,p)+s/2)/s)
-  r,c = p
-  ul=[l(r),l(c)]
-  ur=[l(r),h(c)]
-  ll=[h(r),l(c)]
-  lr=[h(r),h(c)]
-  sum = dist(ul,p)+dist(ur,p)+dist(ll,p)+dist(lr,p)
-  t4 = scale - t(ul,p,sum) - t(ur,p,sum) - t(ll,p,sum);
-  return [[ul,t(ul,p,sum)],[ur,t(ur,p,sum)],
-          [ll,t(ll,p,sum)],[lr,t4]]
-
-def print_mb_taps(angle,blocksize):
-  theta = angle / 57.2957795;
-  affine = [[math.cos(theta),-math.sin(theta)],
-            [math.sin(theta),math.cos(theta)]]
-  radius = (float(blocksize)-1)/2
-  print " // angle of",angle,"degrees"
-  for y in range(blocksize) :
-    for x in range(blocksize) :
-      r,c = numpy.dot(affine,[y-radius, x-radius])
-      tps = gettaps([r+radius,c+radius])
-      for t in tps :
-        p,t = t
-        tr,tc = p
-        print " %2d, %2d, %5d, " % (tr,tc,t,),
-      print " // %2d,%2d " % (y,x)
-
-i=float(sys.argv[1])
-while  i <= float(sys.argv[2]) :
-  print_mb_taps(i,float(sys.argv[4]))
-  i=i+float(sys.argv[3])
-"""
-
-taps = []
-pt=dict()
-ptr=dict()
-for y in range(16) :
-  for x in range(16) :
-    r,c = numpy.dot(affine,[y-7.5, x-7.5])
-    tps = gettaps([r+7.5,c+7.5])
-    j=0
-    for tp in tps : 
-      p,i = tp
-      r,c = p
-      pt[y,x,j]= [p,i]
-      try: 
-        ptr[r,j,c].append([y,x])
-      except:
-        ptr[r,j,c]=[[y,x]]
-      j = j+1 
-
-for key in sorted(pt.keys()) :
-  print key,pt[key]
-
-lr = -99
-lj = -99 
-lc = 0
-
-shuf=""
-mask=""
-for r,j,c in sorted(ptr.keys()) :
-  for y,x in ptr[r,j,c] :
-    if lr != r or lj != j :
-      print "shuf_"+str(lr)+"_"+str(lj)+"_"+shuf.ljust(16,"0"), lc
-      shuf=""
-      lc = 0
-    for i in range(lc,c-1) :
-      shuf = shuf +"0"
-    shuf = shuf + hex(x)[2]
-    lc =c
-    break
-  lr = r
-  lj = j
-#  print r,j,c,ptr[r,j,c]    
-#  print 
-
-for r,j,c in sorted(ptr.keys()) :
-  for y,x in ptr[r,j,c] :
-    print r,j,c,y,x 
-    break
-"""
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 022a429..45ebb2f 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -40,6 +40,8 @@
 #include "vp9/decoder/vp9_reader.h"
 #include "vp9/decoder/vp9_thread.h"
 
+#define MAX_VP9_HEADER_SIZE 80
+
 static int is_compound_reference_allowed(const VP9_COMMON *cm) {
   int i;
   for (i = 1; i < REFS_PER_FRAME; ++i)
@@ -246,8 +248,8 @@
   MACROBLOCKD *const xd = args->xd;
   struct macroblockd_plane *const pd = &xd->plane[plane];
   MODE_INFO *const mi = xd->mi[0];
-  const MB_PREDICTION_MODE mode = (plane == 0) ? get_y_mode(mi, block)
-                                               : mi->mbmi.uv_mode;
+  const PREDICTION_MODE mode = (plane == 0) ? get_y_mode(mi, block)
+                                            : mi->mbmi.uv_mode;
   int x, y;
   uint8_t *dst;
   txfrm_block_to_raster_xy(plane_bsize, tx_size, block, &x, &y);
@@ -451,7 +453,9 @@
                                 const uint8_t *data_end,
                                 size_t read_size,
                                 struct vpx_internal_error_info *error_info,
-                                vp9_reader *r) {
+                                vp9_reader *r,
+                                vpx_decrypt_cb decrypt_cb,
+                                void *decrypt_state) {
   // Validate the calculated partition length. If the buffer
   // described by the partition can't be fully read, then restrict
   // it to the portion that can be (for EC mode) or throw an error.
@@ -459,7 +463,7 @@
     vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
                        "Truncated packet or corrupt tile length");
 
-  if (vp9_reader_init(r, data, read_size))
+  if (vp9_reader_init(r, data, read_size, decrypt_cb, decrypt_state))
     vpx_internal_error(error_info, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate bool decoder %d", 1);
 }
@@ -750,7 +754,9 @@
 static size_t get_tile(const uint8_t *const data_end,
                        int is_last,
                        struct vpx_internal_error_info *error_info,
-                       const uint8_t **data) {
+                       const uint8_t **data,
+                       vpx_decrypt_cb decrypt_cb,
+                       void *decrypt_state) {
   size_t size;
 
   if (!is_last) {
@@ -758,7 +764,13 @@
       vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
                          "Truncated packet or corrupt tile length");
 
-    size = mem_get_be32(*data);
+    if (decrypt_cb) {
+      uint8_t be_data[4];
+      decrypt_cb(decrypt_state, *data, be_data, 4);
+      size = mem_get_be32(be_data);
+    } else {
+      size = mem_get_be32(*data);
+    }
     *data += 4;
 
     if (size > (size_t)(data_end - *data))
@@ -804,7 +816,8 @@
     for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
       const int last_tile = tile_row == tile_rows - 1 &&
                             tile_col == tile_cols - 1;
-      const size_t size = get_tile(data_end, last_tile, &cm->error, &data);
+      const size_t size = get_tile(data_end, last_tile, &cm->error, &data,
+                                   pbi->decrypt_cb, pbi->decrypt_state);
       TileBuffer *const buf = &tile_buffers[tile_row][tile_col];
       buf->data = data;
       buf->size = size;
@@ -823,7 +836,8 @@
       TileInfo tile;
 
       vp9_tile_init(&tile, cm, tile_row, col);
-      setup_token_decoder(buf->data, data_end, buf->size, &cm->error, &r);
+      setup_token_decoder(buf->data, data_end, buf->size, &cm->error, &r,
+                          pbi->decrypt_cb, pbi->decrypt_state);
       decode_tile(pbi, &tile, &r);
 
       if (last_tile)
@@ -921,7 +935,8 @@
   // Load tile data into tile_buffers
   for (n = 0; n < tile_cols; ++n) {
     const size_t size =
-        get_tile(data_end, n == tile_cols - 1, &cm->error, &data);
+        get_tile(data_end, n == tile_cols - 1, &cm->error, &data,
+                 pbi->decrypt_cb, pbi->decrypt_state);
     TileBuffer *const buf = &tile_buffers[n];
     buf->data = data;
     buf->size = size;
@@ -962,7 +977,8 @@
       tile_data->xd.corrupted = 0;
       vp9_tile_init(tile, tile_data->cm, 0, buf->col);
       setup_token_decoder(buf->data, data_end, buf->size, &cm->error,
-                          &tile_data->bit_reader);
+                          &tile_data->bit_reader, pbi->decrypt_cb,
+                          pbi->decrypt_state);
       init_macroblockd(cm, &tile_data->xd);
       vp9_zero(tile_data->xd.dqcoeff);
 
@@ -1163,7 +1179,8 @@
   vp9_reader r;
   int k;
 
-  if (vp9_reader_init(&r, data, partition_size))
+  if (vp9_reader_init(&r, data, partition_size, pbi->decrypt_cb,
+                      pbi->decrypt_state))
     vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate bool decoder 0");
 
@@ -1255,14 +1272,36 @@
 }
 #endif  // NDEBUG
 
+static struct vp9_read_bit_buffer* init_read_bit_buffer(
+    VP9Decoder *pbi,
+    struct vp9_read_bit_buffer *rb,
+    const uint8_t *data,
+    const uint8_t *data_end,
+    uint8_t *clear_data /* buffer size MAX_VP9_HEADER_SIZE */) {
+  rb->bit_offset = 0;
+  rb->error_handler = error_handler;
+  rb->error_handler_data = &pbi->common;
+  if (pbi->decrypt_cb) {
+    const int n = (int)MIN(MAX_VP9_HEADER_SIZE, data_end - data);
+    pbi->decrypt_cb(pbi->decrypt_state, data, clear_data, n);
+    rb->bit_buffer = clear_data;
+    rb->bit_buffer_end = clear_data + n;
+  } else {
+    rb->bit_buffer = data;
+    rb->bit_buffer_end = data_end;
+  }
+  return rb;
+}
+
 int vp9_decode_frame(VP9Decoder *pbi,
                      const uint8_t *data, const uint8_t *data_end,
                      const uint8_t **p_data_end) {
   VP9_COMMON *const cm = &pbi->common;
   MACROBLOCKD *const xd = &pbi->mb;
-
-  struct vp9_read_bit_buffer rb = { data, data_end, 0, cm, error_handler };
-  const size_t first_partition_size = read_uncompressed_header(pbi, &rb);
+  struct vp9_read_bit_buffer rb = { 0 };
+  uint8_t clear_data[MAX_VP9_HEADER_SIZE];
+  const size_t first_partition_size = read_uncompressed_header(pbi,
+      init_read_bit_buffer(pbi, &rb, data, data_end, clear_data));
   const int keyframe = cm->frame_type == KEY_FRAME;
   const int tile_rows = 1 << cm->log2_tile_rows;
   const int tile_cols = 1 << cm->log2_tile_cols;
@@ -1270,9 +1309,9 @@
   xd->cur_buf = new_fb;
 
   if (!first_partition_size) {
-      // showing a frame directly
-      *p_data_end = data + 1;
-      return 0;
+    // showing a frame directly
+    *p_data_end = data + 1;
+    return 0;
   }
 
   if (!pbi->decoded_key_frame && !keyframe)
@@ -1331,7 +1370,8 @@
                          "A stream must start with a complete key frame");
   }
 
-  if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode) {
+  if (!cm->error_resilient_mode && !cm->frame_parallel_decoding_mode &&
+      !new_fb->corrupted) {
     vp9_adapt_coef_probs(cm);
 
     if (!frame_is_intra_only(cm)) {
diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c
index 3618f12..1afaee1 100644
--- a/vp9/decoder/vp9_decodemv.c
+++ b/vp9/decoder/vp9_decodemv.c
@@ -23,30 +23,29 @@
 #include "vp9/decoder/vp9_decodeframe.h"
 #include "vp9/decoder/vp9_reader.h"
 
-static MB_PREDICTION_MODE read_intra_mode(vp9_reader *r, const vp9_prob *p) {
-  return (MB_PREDICTION_MODE)vp9_read_tree(r, vp9_intra_mode_tree, p);
+static PREDICTION_MODE read_intra_mode(vp9_reader *r, const vp9_prob *p) {
+  return (PREDICTION_MODE)vp9_read_tree(r, vp9_intra_mode_tree, p);
 }
 
-static MB_PREDICTION_MODE read_intra_mode_y(VP9_COMMON *cm, vp9_reader *r,
+static PREDICTION_MODE read_intra_mode_y(VP9_COMMON *cm, vp9_reader *r,
                                             int size_group) {
-  const MB_PREDICTION_MODE y_mode = read_intra_mode(r,
-                                        cm->fc.y_mode_prob[size_group]);
+  const PREDICTION_MODE y_mode =
+      read_intra_mode(r, cm->fc.y_mode_prob[size_group]);
   if (!cm->frame_parallel_decoding_mode)
     ++cm->counts.y_mode[size_group][y_mode];
   return y_mode;
 }
 
-static MB_PREDICTION_MODE read_intra_mode_uv(VP9_COMMON *cm, vp9_reader *r,
-                                             MB_PREDICTION_MODE y_mode) {
-  const MB_PREDICTION_MODE uv_mode = read_intra_mode(r,
+static PREDICTION_MODE read_intra_mode_uv(VP9_COMMON *cm, vp9_reader *r,
+                                          PREDICTION_MODE y_mode) {
+  const PREDICTION_MODE uv_mode = read_intra_mode(r,
                                          cm->fc.uv_mode_prob[y_mode]);
   if (!cm->frame_parallel_decoding_mode)
     ++cm->counts.uv_mode[y_mode][uv_mode];
   return uv_mode;
 }
 
-static MB_PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, vp9_reader *r,
-                                          int ctx) {
+static PREDICTION_MODE read_inter_mode(VP9_COMMON *cm, vp9_reader *r, int ctx) {
   const int mode = vp9_read_tree(r, vp9_inter_mode_tree,
                                  cm->fc.inter_mode_probs[ctx]);
   if (!cm->frame_parallel_decoding_mode)
@@ -362,7 +361,7 @@
          mv->col > MV_LOW && mv->col < MV_UPP;
 }
 
-static INLINE int assign_mv(VP9_COMMON *cm, MB_PREDICTION_MODE mode,
+static INLINE int assign_mv(VP9_COMMON *cm, PREDICTION_MODE mode,
                             int_mv mv[2], int_mv ref_mv[2],
                             int_mv nearest_mv[2], int_mv near_mv[2],
                             int is_compound, int allow_hp, vp9_reader *r) {
@@ -469,7 +468,7 @@
     const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize];  // 1 or 2
     const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];  // 1 or 2
     int idx, idy;
-    MB_PREDICTION_MODE b_mode;
+    PREDICTION_MODE b_mode;
     int_mv nearest_sub8x8[2], near_sub8x8[2];
     for (idy = 0; idy < 2; idy += num_4x4_h) {
       for (idx = 0; idx < 2; idx += num_4x4_w) {
diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c
index fd74478..abcff9f 100644
--- a/vp9/decoder/vp9_decoder.c
+++ b/vp9/decoder/vp9_decoder.c
@@ -32,74 +32,6 @@
 #include "vp9/decoder/vp9_detokenize.h"
 #include "vp9/decoder/vp9_dthread.h"
 
-#define WRITE_RECON_BUFFER 0
-#if WRITE_RECON_BUFFER == 1
-static void recon_write_yuv_frame(const char *name,
-                                  const YV12_BUFFER_CONFIG *s,
-                                  int w, int _h) {
-  FILE *yuv_file = fopen(name, "ab");
-  const uint8_t *src = s->y_buffer;
-  int h = _h;
-
-  do {
-    fwrite(src, w, 1,  yuv_file);
-    src += s->y_stride;
-  } while (--h);
-
-  src = s->u_buffer;
-  h = (_h + 1) >> 1;
-  w = (w + 1) >> 1;
-
-  do {
-    fwrite(src, w, 1,  yuv_file);
-    src += s->uv_stride;
-  } while (--h);
-
-  src = s->v_buffer;
-  h = (_h + 1) >> 1;
-
-  do {
-    fwrite(src, w, 1, yuv_file);
-    src += s->uv_stride;
-  } while (--h);
-
-  fclose(yuv_file);
-}
-#endif
-#if WRITE_RECON_BUFFER == 2
-void write_dx_frame_to_file(YV12_BUFFER_CONFIG *frame, int this_frame) {
-  // write the frame
-  FILE *yframe;
-  int i;
-  char filename[255];
-
-  snprintf(filename, sizeof(filename)-1, "dx\\y%04d.raw", this_frame);
-  yframe = fopen(filename, "wb");
-
-  for (i = 0; i < frame->y_height; i++)
-    fwrite(frame->y_buffer + i * frame->y_stride,
-           frame->y_width, 1, yframe);
-
-  fclose(yframe);
-  snprintf(filename, sizeof(filename)-1, "dx\\u%04d.raw", this_frame);
-  yframe = fopen(filename, "wb");
-
-  for (i = 0; i < frame->uv_height; i++)
-    fwrite(frame->u_buffer + i * frame->uv_stride,
-           frame->uv_width, 1, yframe);
-
-  fclose(yframe);
-  snprintf(filename, sizeof(filename)-1, "dx\\v%04d.raw", this_frame);
-  yframe = fopen(filename, "wb");
-
-  for (i = 0; i < frame->uv_height; i++)
-    fwrite(frame->v_buffer + i * frame->uv_stride,
-           frame->uv_width, 1, yframe);
-
-  fclose(yframe);
-}
-#endif
-
 void vp9_initialize_dec() {
   static int init_done = 0;
 
@@ -110,7 +42,7 @@
   }
 }
 
-VP9Decoder *vp9_decoder_create(const VP9D_CONFIG *oxcf) {
+VP9Decoder *vp9_decoder_create(const VP9DecoderConfig *oxcf) {
   VP9Decoder *const pbi = vpx_memalign(32, sizeof(*pbi));
   VP9_COMMON *const cm = pbi ? &pbi->common : NULL;
 
@@ -348,40 +280,16 @@
 
   swap_frame_buffers(pbi);
 
-#if WRITE_RECON_BUFFER == 2
-  if (cm->show_frame)
-    write_dx_frame_to_file(cm->frame_to_show,
-                           cm->current_video_frame);
-  else
-    write_dx_frame_to_file(cm->frame_to_show,
-                           cm->current_video_frame + 1000);
-#endif
-
   if (!pbi->do_loopfilter_inline) {
     // If multiple threads are used to decode tiles, then we use those threads
     // to do parallel loopfiltering.
     if (pbi->num_tile_workers) {
-      vp9_loop_filter_frame_mt(pbi, cm, &pbi->mb, cm->lf.filter_level, 0, 0);
+      vp9_loop_filter_frame_mt(pbi, cm, cm->lf.filter_level, 0, 0);
     } else {
       vp9_loop_filter_frame(cm, &pbi->mb, cm->lf.filter_level, 0, 0);
     }
   }
 
-#if WRITE_RECON_BUFFER == 2
-  if (cm->show_frame)
-    write_dx_frame_to_file(cm->frame_to_show,
-                           cm->current_video_frame + 2000);
-  else
-    write_dx_frame_to_file(cm->frame_to_show,
-                           cm->current_video_frame + 3000);
-#endif
-
-#if WRITE_RECON_BUFFER == 1
-  if (cm->show_frame)
-    recon_write_yuv_frame("recon.yuv", cm->frame_to_show,
-                          cm->width, cm->height);
-#endif
-
   vp9_clear_system_state();
 
   cm->last_width = cm->width;
@@ -423,10 +331,6 @@
   ret = vp9_post_proc_frame(&pbi->common, sd, flags);
 #else
     *sd = *pbi->common.frame_to_show;
-    sd->y_width = pbi->common.width;
-    sd->y_height = pbi->common.height;
-    sd->uv_width = sd->y_width >> pbi->common.subsampling_x;
-    sd->uv_height = sd->y_height >> pbi->common.subsampling_y;
     ret = 0;
 #endif /*!CONFIG_POSTPROC*/
   vp9_clear_system_state();
diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h
index c9dc251..ebcbb90 100644
--- a/vp9/decoder/vp9_decoder.h
+++ b/vp9/decoder/vp9_decoder.h
@@ -27,20 +27,20 @@
 extern "C" {
 #endif
 
-typedef struct {
+typedef struct VP9DecoderConfig {
   int width;
   int height;
   int version;
   int max_threads;
   int inv_tile_order;
-} VP9D_CONFIG;
+} VP9DecoderConfig;
 
 typedef struct VP9Decoder {
   DECLARE_ALIGNED(16, MACROBLOCKD, mb);
 
   DECLARE_ALIGNED(16, VP9_COMMON, common);
 
-  VP9D_CONFIG oxcf;
+  VP9DecoderConfig oxcf;
 
   int64_t last_time_stamp;
   int ready_for_new_data;
@@ -49,9 +49,6 @@
 
   int decoded_key_frame;
 
-  int initial_width;
-  int initial_height;
-
   int do_loopfilter_inline;  // apply loopfilter to available rows immediately
   VP9Worker lf_worker;
 
@@ -59,6 +56,9 @@
   int num_tile_workers;
 
   VP9LfSync lf_row_sync;
+
+  vpx_decrypt_cb decrypt_cb;
+  void *decrypt_state;
 } VP9Decoder;
 
 void vp9_initialize_dec();
@@ -84,7 +84,7 @@
                           int index, YV12_BUFFER_CONFIG **fb);
 
 
-struct VP9Decoder *vp9_decoder_create(const VP9D_CONFIG *oxcf);
+struct VP9Decoder *vp9_decoder_create(const VP9DecoderConfig *oxcf);
 
 void vp9_decoder_remove(struct VP9Decoder *pbi);
 
diff --git a/vp9/decoder/vp9_dsubexp.c b/vp9/decoder/vp9_dsubexp.c
index e67b372..c22617e 100644
--- a/vp9/decoder/vp9_dsubexp.c
+++ b/vp9/decoder/vp9_dsubexp.c
@@ -26,22 +26,6 @@
   return v < m ?  v : (v << 1) - m + vp9_read_bit(r);
 }
 
-
-static int merge_index(int v, int n, int modulus) {
-  int max1 = (n - 1 - modulus / 2) / modulus + 1;
-  if (v < max1) {
-    v = v * modulus + modulus / 2;
-  } else {
-    int w;
-    v -= max1;
-    w = v;
-    v += (v + modulus - modulus / 2) / modulus;
-    while (v % modulus == modulus / 2 ||
-           w != v - (v + modulus - modulus / 2) / modulus) v++;
-  }
-  return v;
-}
-
 static int inv_remap_prob(int v, int m) {
   static int inv_map_table[MAX_PROB - 1] = {
       6,  19,  32,  45,  58,  71,  84,  97, 110, 123, 136, 149, 162, 175, 188,
diff --git a/vp9/decoder/vp9_dthread.c b/vp9/decoder/vp9_dthread.c
index 9b124c9..9098063 100644
--- a/vp9/decoder/vp9_dthread.c
+++ b/vp9/decoder/vp9_dthread.c
@@ -40,13 +40,13 @@
   const int nsync = lf_sync->sync_range;
 
   if (r && !(c & (nsync - 1))) {
-    mutex_lock(&lf_sync->mutex_[r - 1]);
+    pthread_mutex_t *const mutex = &lf_sync->mutex_[r - 1];
+    mutex_lock(mutex);
 
     while (c > lf_sync->cur_sb_col[r - 1] - nsync) {
-      pthread_cond_wait(&lf_sync->cond_[r - 1],
-                        &lf_sync->mutex_[r - 1]);
+      pthread_cond_wait(&lf_sync->cond_[r - 1], mutex);
     }
-    pthread_mutex_unlock(&lf_sync->mutex_[r - 1]);
+    pthread_mutex_unlock(mutex);
   }
 #else
   (void)lf_sync;
@@ -94,21 +94,21 @@
                                 VP9LfSync *const lf_sync, int num_lf_workers) {
   const int num_planes = y_only ? 1 : MAX_MB_PLANE;
   int r, c;  // SB row and col
-  LOOP_FILTER_MASK lfm;
   const int sb_cols = mi_cols_aligned_to_sb(cm->mi_cols) >> MI_BLOCK_SIZE_LOG2;
 
   for (r = start; r < stop; r += num_lf_workers) {
     const int mi_row = r << MI_BLOCK_SIZE_LOG2;
-    MODE_INFO **mi_8x8 = cm->mi_grid_visible + mi_row * cm->mi_stride;
+    MODE_INFO **const mi = cm->mi_grid_visible + mi_row * cm->mi_stride;
 
     for (c = 0; c < sb_cols; ++c) {
       const int mi_col = c << MI_BLOCK_SIZE_LOG2;
+      LOOP_FILTER_MASK lfm;
       int plane;
 
       sync_read(lf_sync, r, c);
 
       vp9_setup_dst_planes(xd, frame_buffer, mi_row, mi_col);
-      vp9_setup_mask(cm, mi_row, mi_col, mi_8x8 + mi_col, cm->mi_stride, &lfm);
+      vp9_setup_mask(cm, mi_row, mi_col, mi + mi_col, cm->mi_stride, &lfm);
 
       for (plane = 0; plane < num_planes; ++plane) {
         vp9_filter_block_plane(cm, &xd->plane[plane], mi_row, &lfm);
@@ -134,9 +134,9 @@
 // threads.
 void vp9_loop_filter_frame_mt(VP9Decoder *pbi,
                               VP9_COMMON *cm,
-                              MACROBLOCKD *xd,
                               int frame_filter_level,
                               int y_only, int partial_frame) {
+  VP9LfSync *const lf_sync = &pbi->lf_row_sync;
   // Number of superblock rows and cols
   const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
   const int tile_cols = 1 << cm->log2_tile_cols;
@@ -146,8 +146,6 @@
   // Allocate memory used in thread synchronization.
   // This always needs to be done even if frame_filter_level is 0.
   if (!cm->current_video_frame || cm->last_height != cm->height) {
-    VP9LfSync *const lf_sync = &pbi->lf_row_sync;
-
     if (cm->last_height != cm->height) {
       const int aligned_last_height =
           ALIGN_POWER_OF_TWO(cm->last_height, MI_SIZE_LOG2);
@@ -166,8 +164,7 @@
   vp9_loop_filter_frame_init(cm, frame_filter_level);
 
   // Initialize cur_sb_col to -1 for all SB rows.
-  vpx_memset(pbi->lf_row_sync.cur_sb_col, -1,
-             sizeof(*pbi->lf_row_sync.cur_sb_col) * sb_rows);
+  vpx_memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
 
   // Set up loopfilter thread data.
   // The decoder is using num_workers instead of pbi->num_tile_workers
@@ -194,7 +191,7 @@
     lf_data->stop = sb_rows;
     lf_data->y_only = y_only;   // always do all planes in decoder
 
-    lf_data->lf_sync = &pbi->lf_row_sync;
+    lf_data->lf_sync = lf_sync;
     lf_data->num_lf_workers = num_workers;
 
     // Start loopfiltering
@@ -253,8 +250,12 @@
 
 // Deallocate lf synchronization related mutex and data
 void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows) {
-#if CONFIG_MULTITHREAD
+#if !CONFIG_MULTITHREAD
+  (void)rows;
+#endif  // !CONFIG_MULTITHREAD
+
   if (lf_sync != NULL) {
+#if CONFIG_MULTITHREAD
     int i;
 
     if (lf_sync->mutex_ != NULL) {
@@ -269,17 +270,10 @@
       }
       vpx_free(lf_sync->cond_);
     }
-
+#endif  // CONFIG_MULTITHREAD
     vpx_free(lf_sync->cur_sb_col);
     // clear the structure as the source of this call may be a resize in which
     // case this call will be followed by an _alloc() which may fail.
-    vpx_memset(lf_sync, 0, sizeof(*lf_sync));
+    vp9_zero(*lf_sync);
   }
-#else
-  (void)rows;
-  if (lf_sync != NULL) {
-    vpx_free(lf_sync->cur_sb_col);
-    vpx_memset(lf_sync, 0, sizeof(*lf_sync));
-  }
-#endif  // CONFIG_MULTITHREAD
 }
diff --git a/vp9/decoder/vp9_dthread.h b/vp9/decoder/vp9_dthread.h
index 005bd7b..8738cee 100644
--- a/vp9/decoder/vp9_dthread.h
+++ b/vp9/decoder/vp9_dthread.h
@@ -12,11 +12,9 @@
 #define VP9_DECODER_VP9_DTHREAD_H_
 
 #include "./vpx_config.h"
-#include "vp9/common/vp9_loopfilter.h"
 #include "vp9/decoder/vp9_reader.h"
 #include "vp9/decoder/vp9_thread.h"
 
-struct macroblockd;
 struct VP9Common;
 struct VP9Decoder;
 
@@ -43,16 +41,15 @@
 } VP9LfSync;
 
 // Allocate memory for loopfilter row synchronization.
-void vp9_loop_filter_alloc(struct VP9Common *cm, struct VP9LfSyncData *lf_sync,
+void vp9_loop_filter_alloc(struct VP9Common *cm, VP9LfSync *lf_sync,
                            int rows, int width);
 
 // Deallocate loopfilter synchronization related mutex and data.
-void vp9_loop_filter_dealloc(struct VP9LfSyncData *lf_sync, int rows);
+void vp9_loop_filter_dealloc(VP9LfSync *lf_sync, int rows);
 
 // Multi-threaded loopfilter that uses the tile threads.
 void vp9_loop_filter_frame_mt(struct VP9Decoder *pbi,
                               struct VP9Common *cm,
-                              struct macroblockd *xd,
                               int frame_filter_level,
                               int y_only, int partial_frame);
 
diff --git a/vp9/decoder/vp9_reader.c b/vp9/decoder/vp9_reader.c
index fb44c88..6bb4f9f 100644
--- a/vp9/decoder/vp9_reader.c
+++ b/vp9/decoder/vp9_reader.c
@@ -18,7 +18,11 @@
 // Even relatively modest values like 100 would work fine.
 #define LOTS_OF_BITS 0x40000000
 
-int vp9_reader_init(vp9_reader *r, const uint8_t *buffer, size_t size) {
+int vp9_reader_init(vp9_reader *r,
+                    const uint8_t *buffer,
+                    size_t size,
+                    vpx_decrypt_cb decrypt_cb,
+                    void *decrypt_state) {
   if (size && !buffer) {
     return 1;
   } else {
@@ -27,6 +31,8 @@
     r->value = 0;
     r->count = -8;
     r->range = 255;
+    r->decrypt_cb = decrypt_cb;
+    r->decrypt_state = decrypt_state;
     vp9_reader_fill(r);
     return vp9_read_bit(r) != 0;  // marker bit
   }
@@ -35,12 +41,21 @@
 void vp9_reader_fill(vp9_reader *r) {
   const uint8_t *const buffer_end = r->buffer_end;
   const uint8_t *buffer = r->buffer;
+  const uint8_t *buffer_start = buffer;
   BD_VALUE value = r->value;
   int count = r->count;
   int shift = BD_VALUE_SIZE - CHAR_BIT - (count + CHAR_BIT);
   int loop_end = 0;
-  const int bits_left = (int)((buffer_end - buffer) * CHAR_BIT);
-  const int x = shift + CHAR_BIT - bits_left;
+  const size_t bytes_left = buffer_end - buffer;
+  const size_t bits_left = bytes_left * CHAR_BIT;
+  const int x = (int)(shift + CHAR_BIT - bits_left);
+
+  if (r->decrypt_cb) {
+    size_t n = MIN(sizeof(r->clear_buffer), bytes_left);
+    r->decrypt_cb(r->decrypt_state, buffer, r->clear_buffer, (int)n);
+    buffer = r->clear_buffer;
+    buffer_start = r->clear_buffer;
+  }
 
   if (x >= 0) {
     count += LOTS_OF_BITS;
@@ -55,7 +70,10 @@
     }
   }
 
-  r->buffer = buffer;
+  // NOTE: Variable 'buffer' may not relate to 'r->buffer' after decryption,
+  // so we increase 'r->buffer' by the amount that 'buffer' moved, rather than
+  // assign 'buffer' to 'r->buffer'.
+  r->buffer += buffer - buffer_start;
   r->value = value;
   r->count = count;
 }
diff --git a/vp9/decoder/vp9_reader.h b/vp9/decoder/vp9_reader.h
index 8fe6acb..32e200e 100644
--- a/vp9/decoder/vp9_reader.h
+++ b/vp9/decoder/vp9_reader.h
@@ -16,6 +16,7 @@
 
 #include "./vpx_config.h"
 #include "vpx_ports/mem.h"
+#include "vpx/vp8dx.h"
 #include "vpx/vpx_integer.h"
 
 #include "vp9/common/vp9_prob.h"
@@ -31,12 +32,19 @@
 typedef struct {
   const uint8_t *buffer_end;
   const uint8_t *buffer;
+  uint8_t clear_buffer[sizeof(BD_VALUE) + 1];
   BD_VALUE value;
   int count;
   unsigned int range;
+  vpx_decrypt_cb decrypt_cb;
+  void *decrypt_state;
 } vp9_reader;
 
-int vp9_reader_init(vp9_reader *r, const uint8_t *buffer, size_t size);
+int vp9_reader_init(vp9_reader *r,
+                    const uint8_t *buffer,
+                    size_t size,
+                    vpx_decrypt_cb decrypt_cb,
+                    void *decrypt_state);
 
 void vp9_reader_fill(vp9_reader *r);
 
diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c
index 7879091..d1437d3 100644
--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -72,7 +72,7 @@
   // Turn off cyclic refresh if bits available per frame is not sufficiently
   // larger than bit cost of segmentation. Segment map bit cost should scale
   // with number of seg blocks, so compare available bits to number of blocks.
-  // Average bits available per frame = av_per_frame_bandwidth
+  // Average bits available per frame = avg_frame_bandwidth
   // Number of (8x8) blocks in frame = mi_rows * mi_cols;
   const float factor  = 0.5;
   const int number_blocks = cm->mi_rows  * cm->mi_cols;
@@ -80,7 +80,7 @@
   // ~24kbps for CIF, 72kbps for VGA (at 30fps).
   // Also turn off at very small frame sizes, to avoid too large fraction of
   // superblocks to be refreshed per frame. Threshold below is less than QCIF.
-  if (rc->av_per_frame_bandwidth < factor * number_blocks ||
+  if (rc->avg_frame_bandwidth < factor * number_blocks ||
       number_blocks / 64 < 5)
     return 0;
   else
@@ -136,7 +136,8 @@
   const int xmis = MIN(cm->mi_cols - mi_col, bw);
   const int ymis = MIN(cm->mi_rows - mi_row, bh);
   const int block_index = mi_row * cm->mi_cols + mi_col;
-  const int refresh_this_block = candidate_refresh_aq(cr, mbmi, bsize, use_rd);
+  const int refresh_this_block = cpi->mb.in_static_area ||
+                                 candidate_refresh_aq(cr, mbmi, bsize, use_rd);
   // Default is to not update the refresh map.
   int new_map_value = cr->map[block_index];
   int x = 0; int y = 0;
@@ -200,6 +201,7 @@
 
     // Rate target ratio to set q delta.
     const float rate_ratio_qdelta = 2.0;
+    const double q = vp9_convert_qindex_to_q(cm->base_qindex);
     vp9_clear_system_state();
     // Some of these parameters may be set via codec-control function later.
     cr->max_sbs_perframe = 10;
@@ -209,14 +211,12 @@
     // Set rate threshold to some fraction of target (and scaled by 256).
     cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 2;
     // Distortion threshold, quadratic in Q, scale factor to be adjusted.
-    cr->thresh_dist_sb = 8 * (int)(vp9_convert_qindex_to_q(cm->base_qindex) *
-        vp9_convert_qindex_to_q(cm->base_qindex));
+    cr->thresh_dist_sb = 8 * (int)(q * q);
     if (cpi->sf.use_nonrd_pick_mode) {
       // May want to be more conservative with thresholds in non-rd mode for now
       // as rate/distortion are derived from model based on prediction residual.
       cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 3;
-      cr->thresh_dist_sb = 4 * (int)(vp9_convert_qindex_to_q(cm->base_qindex) *
-          vp9_convert_qindex_to_q(cm->base_qindex));
+      cr->thresh_dist_sb = 4 * (int)(q * q);
     }
 
     cr->num_seg_blocks = 0;
diff --git a/vp9/encoder/vp9_aq_variance.h b/vp9/encoder/vp9_aq_variance.h
index 381fe50..d1a459f 100644
--- a/vp9/encoder/vp9_aq_variance.h
+++ b/vp9/encoder/vp9_aq_variance.h
@@ -12,7 +12,7 @@
 #ifndef VP9_ENCODER_VP9_AQ_VARIANCE_H_
 #define VP9_ENCODER_VP9_AQ_VARIANCE_H_
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index 8d2afb9..c5a85c9 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -47,12 +47,12 @@
   vp9_tokens_from_tree(inter_mode_encodings, vp9_inter_mode_tree);
 }
 
-static void write_intra_mode(vp9_writer *w, MB_PREDICTION_MODE mode,
+static void write_intra_mode(vp9_writer *w, PREDICTION_MODE mode,
                              const vp9_prob *probs) {
   vp9_write_token(w, vp9_intra_mode_tree, probs, &intra_mode_encodings[mode]);
 }
 
-static void write_inter_mode(vp9_writer *w, MB_PREDICTION_MODE mode,
+static void write_inter_mode(vp9_writer *w, PREDICTION_MODE mode,
                              const vp9_prob *probs) {
   assert(is_inter_mode(mode));
   vp9_write_token(w, vp9_inter_mode_tree, probs,
@@ -233,7 +233,7 @@
   const MACROBLOCKD *const xd = &x->e_mbd;
   const struct segmentation *const seg = &cm->seg;
   const MB_MODE_INFO *const mbmi = &mi->mbmi;
-  const MB_PREDICTION_MODE mode = mbmi->mode;
+  const PREDICTION_MODE mode = mbmi->mode;
   const int segment_id = mbmi->segment_id;
   const BLOCK_SIZE bsize = mbmi->sb_type;
   const int allow_hp = cm->allow_high_precision_mv;
@@ -273,7 +273,7 @@
       const int num_4x4_h = num_4x4_blocks_high_lookup[bsize];
       for (idy = 0; idy < 2; idy += num_4x4_h) {
         for (idx = 0; idx < 2; idx += num_4x4_w) {
-          const MB_PREDICTION_MODE b_mode = mi->bmi[idy * 2 + idx].as_mode;
+          const PREDICTION_MODE b_mode = mi->bmi[idy * 2 + idx].as_mode;
           write_intra_mode(w, b_mode, cm->fc.y_mode_prob[0]);
         }
       }
@@ -308,7 +308,7 @@
       for (idy = 0; idy < 2; idy += num_4x4_h) {
         for (idx = 0; idx < 2; idx += num_4x4_w) {
           const int j = idy * 2 + idx;
-          const MB_PREDICTION_MODE b_mode = mi->bmi[j].as_mode;
+          const PREDICTION_MODE b_mode = mi->bmi[j].as_mode;
           write_inter_mode(w, b_mode, inter_probs);
           ++cm->counts.inter_mode[mode_ctx][INTER_OFFSET(b_mode)];
           if (b_mode == NEWMV) {
@@ -903,7 +903,7 @@
       // other uses are implemented (like RTC/temporal scaling)
       //
       // gld_fb_idx and alt_fb_idx need to be swapped for future frames, but
-      // that happens in vp9_onyx_if.c:update_reference_frames() so that it can
+      // that happens in vp9_encoder.c:update_reference_frames() so that it can
       // be done outside of the recode loop.
       return (cpi->refresh_last_frame << cpi->lst_fb_idx) |
              (cpi->refresh_golden_frame << cpi->alt_fb_idx);
diff --git a/vp9/encoder/vp9_block.h b/vp9/encoder/vp9_block.h
index 7729d84..f35a85f 100644
--- a/vp9/encoder/vp9_block.h
+++ b/vp9/encoder/vp9_block.h
@@ -20,12 +20,6 @@
 extern "C" {
 #endif
 
-// motion search site
-typedef struct {
-  MV mv;
-  int offset;
-} search_site;
-
 // Structure to hold snapshot of coding context during the mode picking process
 typedef struct {
   MODE_INFO mic;
@@ -79,6 +73,18 @@
   // Zbin Over Quant value
   int16_t zbin_extra;
 };
+typedef struct PC_TREE {
+  int index;
+  PARTITION_TYPE partitioning;
+  BLOCK_SIZE block_size;
+  PICK_MODE_CONTEXT none;
+  PICK_MODE_CONTEXT horizontal[2];
+  PICK_MODE_CONTEXT vertical[2];
+  union {
+    struct PC_TREE *split[4];
+    PICK_MODE_CONTEXT *leaf_split[4];
+  };
+} PC_TREE;
 
 /* The [2] dimension is for whether we skip the EOB node (i.e. if previous
  * coefficient in this block was zero) or not. */
@@ -96,19 +102,12 @@
   int skip_optimize;
   int q_index;
 
-  search_site *ss;
-  int ss_count;
-  int searches_per_step;
-
   int errorperbit;
   int sadperbit16;
   int sadperbit4;
   int rddiv;
   int rdmult;
   unsigned int mb_energy;
-  unsigned int *mb_activity_ptr;
-  int *mb_norm_activity_ptr;
-  signed int act_zbin_adj;
 
   int mv_best_ref_index[MAX_REF_FRAMES];
   unsigned int max_mv_context[MAX_REF_FRAMES];
@@ -136,11 +135,6 @@
   int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES];
   int switchable_interp_costs[SWITCHABLE_FILTER_CONTEXTS][SWITCHABLE_FILTERS];
 
-  unsigned char sb_index;   // index of 32x32 block inside the 64x64 block
-  unsigned char mb_index;   // index of 16x16 block inside the 32x32 block
-  unsigned char b_index;    // index of 8x8 block inside the 16x16 block
-  unsigned char ab_index;   // index of 4x4 block inside the 8x8 block
-
   // These define limits to motion vector components to prevent them
   // from extending outside the UMV borders
   int mv_col_min;
@@ -158,6 +152,8 @@
   // note that token_costs is the cost when eob node is skipped
   vp9_coeff_cost token_costs[TX_SIZES];
 
+  int in_static_area;
+
   int optimize;
 
   // indicate if it is in the rd search loop or encoding process
@@ -167,69 +163,14 @@
   // Used to store sub partition's choices.
   int_mv pred_mv[MAX_REF_FRAMES];
 
-  // TODO(jingning): Need to refactor the structure arrays that buffers the
-  // coding mode decisions of each partition type.
-  PICK_MODE_CONTEXT ab4x4_context[4][4][4];
-  PICK_MODE_CONTEXT sb8x4_context[4][4][4];
-  PICK_MODE_CONTEXT sb4x8_context[4][4][4];
-  PICK_MODE_CONTEXT sb8x8_context[4][4][4];
-  PICK_MODE_CONTEXT sb8x16_context[4][4][2];
-  PICK_MODE_CONTEXT sb16x8_context[4][4][2];
-  PICK_MODE_CONTEXT mb_context[4][4];
-  PICK_MODE_CONTEXT sb32x16_context[4][2];
-  PICK_MODE_CONTEXT sb16x32_context[4][2];
-  // when 4 MBs share coding parameters:
-  PICK_MODE_CONTEXT sb32_context[4];
-  PICK_MODE_CONTEXT sb32x64_context[2];
-  PICK_MODE_CONTEXT sb64x32_context[2];
-  PICK_MODE_CONTEXT sb64_context;
+  PICK_MODE_CONTEXT *leaf_tree;
+  PC_TREE *pc_tree;
+  PC_TREE *pc_root;
   int partition_cost[PARTITION_CONTEXTS][PARTITION_TYPES];
 
-  BLOCK_SIZE b_partitioning[4][4][4];
-  BLOCK_SIZE mb_partitioning[4][4];
-  BLOCK_SIZE sb_partitioning[4];
-  BLOCK_SIZE sb64_partitioning;
-
   void (*fwd_txm4x4)(const int16_t *input, int16_t *output, int stride);
 };
 
-// TODO(jingning): the variables used here are little complicated. need further
-// refactoring on organizing the temporary buffers, when recursive
-// partition down to 4x4 block size is enabled.
-static INLINE PICK_MODE_CONTEXT *get_block_context(MACROBLOCK *x,
-                                                   BLOCK_SIZE bsize) {
-  switch (bsize) {
-    case BLOCK_64X64:
-      return &x->sb64_context;
-    case BLOCK_64X32:
-      return &x->sb64x32_context[x->sb_index];
-    case BLOCK_32X64:
-      return &x->sb32x64_context[x->sb_index];
-    case BLOCK_32X32:
-      return &x->sb32_context[x->sb_index];
-    case BLOCK_32X16:
-      return &x->sb32x16_context[x->sb_index][x->mb_index];
-    case BLOCK_16X32:
-      return &x->sb16x32_context[x->sb_index][x->mb_index];
-    case BLOCK_16X16:
-      return &x->mb_context[x->sb_index][x->mb_index];
-    case BLOCK_16X8:
-      return &x->sb16x8_context[x->sb_index][x->mb_index][x->b_index];
-    case BLOCK_8X16:
-      return &x->sb8x16_context[x->sb_index][x->mb_index][x->b_index];
-    case BLOCK_8X8:
-      return &x->sb8x8_context[x->sb_index][x->mb_index][x->b_index];
-    case BLOCK_8X4:
-      return &x->sb8x4_context[x->sb_index][x->mb_index][x->b_index];
-    case BLOCK_4X8:
-      return &x->sb4x8_context[x->sb_index][x->mb_index][x->b_index];
-    case BLOCK_4X4:
-      return &x->ab4x4_context[x->sb_index][x->mb_index][x->b_index];
-    default:
-      assert(0);
-      return NULL;
-  }
-}
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/vp9/encoder/vp9_context_tree.c b/vp9/encoder/vp9_context_tree.c
new file mode 100644
index 0000000..659935c
--- /dev/null
+++ b/vp9/encoder/vp9_context_tree.c
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+
+#include "vp9/encoder/vp9_context_tree.h"
+
+static const BLOCK_SIZE square[] = {
+    BLOCK_8X8,
+    BLOCK_16X16,
+    BLOCK_32X32,
+    BLOCK_64X64,
+};
+
+static void alloc_mode_context(VP9_COMMON *cm, int num_4x4_blk,
+                               PICK_MODE_CONTEXT *ctx) {
+  const int num_blk = (num_4x4_blk < 4 ? 4 : num_4x4_blk);
+  const int num_pix = num_blk << 4;
+  int i, k;
+  ctx->num_4x4_blk = num_blk;
+
+  CHECK_MEM_ERROR(cm, ctx->zcoeff_blk,
+                  vpx_calloc(num_4x4_blk, sizeof(uint8_t)));
+  for (i = 0; i < MAX_MB_PLANE; ++i) {
+    for (k = 0; k < 3; ++k) {
+      CHECK_MEM_ERROR(cm, ctx->coeff[i][k],
+                      vpx_memalign(16, num_pix * sizeof(int16_t)));
+      CHECK_MEM_ERROR(cm, ctx->qcoeff[i][k],
+                      vpx_memalign(16, num_pix * sizeof(int16_t)));
+      CHECK_MEM_ERROR(cm, ctx->dqcoeff[i][k],
+                      vpx_memalign(16, num_pix * sizeof(int16_t)));
+      CHECK_MEM_ERROR(cm, ctx->eobs[i][k],
+                      vpx_memalign(16, num_pix * sizeof(uint16_t)));
+      ctx->coeff_pbuf[i][k]   = ctx->coeff[i][k];
+      ctx->qcoeff_pbuf[i][k]  = ctx->qcoeff[i][k];
+      ctx->dqcoeff_pbuf[i][k] = ctx->dqcoeff[i][k];
+      ctx->eobs_pbuf[i][k]    = ctx->eobs[i][k];
+    }
+  }
+}
+
+static void free_mode_context(PICK_MODE_CONTEXT *ctx) {
+  int i, k;
+  vpx_free(ctx->zcoeff_blk);
+  ctx->zcoeff_blk = 0;
+  for (i = 0; i < MAX_MB_PLANE; ++i) {
+    for (k = 0; k < 3; ++k) {
+      vpx_free(ctx->coeff[i][k]);
+      ctx->coeff[i][k] = 0;
+      vpx_free(ctx->qcoeff[i][k]);
+      ctx->qcoeff[i][k] = 0;
+      vpx_free(ctx->dqcoeff[i][k]);
+      ctx->dqcoeff[i][k] = 0;
+      vpx_free(ctx->eobs[i][k]);
+      ctx->eobs[i][k] = 0;
+    }
+  }
+}
+static void free_tree_contexts(PC_TREE *this_pc) {
+  free_mode_context(&this_pc->none);
+  free_mode_context(&this_pc->horizontal[0]);
+  free_mode_context(&this_pc->horizontal[1]);
+  free_mode_context(&this_pc->vertical[0]);
+  free_mode_context(&this_pc->vertical[1]);
+}
+static void alloc_tree_contexts(VP9_COMMON *cm, PC_TREE *this_pc,
+                                int num_4x4_blk) {
+  alloc_mode_context(cm, num_4x4_blk, &this_pc->none);
+  alloc_mode_context(cm, num_4x4_blk/2, &this_pc->horizontal[0]);
+  alloc_mode_context(cm, num_4x4_blk/2, &this_pc->vertical[0]);
+
+  /* TODO(Jbb): for 4x8 and 8x4 these allocated values are not used.
+   * Figure out a better way to do this. */
+  alloc_mode_context(cm, num_4x4_blk/2, &this_pc->horizontal[1]);
+  alloc_mode_context(cm, num_4x4_blk/2, &this_pc->vertical[1]);
+}
+
+// This function sets up a tree of contexts such that at each square
+// partition level. There are contexts for none, horizontal, vertical, and
+// split.  Along with a block_size value and a selected block_size which
+// represents the state of our search.
+void vp9_setup_pc_tree(VP9_COMMON *cm, MACROBLOCK *x) {
+  int i, j;
+  const int leaf_nodes = 64;
+  const int tree_nodes = 64 + 16 + 4 + 1;
+  int pc_tree_index = 0;
+  PC_TREE *this_pc;
+  PICK_MODE_CONTEXT *this_leaf;
+  int square_index = 1;
+  int nodes;
+
+  vpx_free(x->leaf_tree);
+  CHECK_MEM_ERROR(cm, x->leaf_tree, vpx_calloc(leaf_nodes,
+                                               sizeof(PICK_MODE_CONTEXT)));
+  vpx_free(x->pc_tree);
+  CHECK_MEM_ERROR(cm, x->pc_tree, vpx_calloc(tree_nodes, sizeof(PC_TREE)));
+
+  this_pc = &x->pc_tree[0];
+  this_leaf = &x->leaf_tree[0];
+
+  // 4x4 blocks smaller than 8x8 but in the same 8x8 block share the same
+  // context so we only need to allocate 1 for each 8x8 block.
+  for (i = 0; i < leaf_nodes; ++i)
+    alloc_mode_context(cm, 1, &x->leaf_tree[i]);
+
+  // Sets up all the leaf nodes in the tree.
+  for (pc_tree_index = 0; pc_tree_index < leaf_nodes; ++pc_tree_index) {
+    x->pc_tree[pc_tree_index].block_size = square[0];
+    alloc_tree_contexts(cm, &x->pc_tree[pc_tree_index], 4);
+    x->pc_tree[pc_tree_index].leaf_split[0] = this_leaf++;
+    for (j = 1; j < 4; j++) {
+      x->pc_tree[pc_tree_index].leaf_split[j] =
+          x->pc_tree[pc_tree_index].leaf_split[0];
+    }
+  }
+
+  // Each node has 4 leaf nodes, fill each block_size level of the tree
+  // from leafs to the root.
+  for (nodes = 16; nodes > 0; nodes >>= 2, ++square_index) {
+    for (i = 0; i < nodes; ++pc_tree_index,  ++i) {
+      alloc_tree_contexts(cm, &x->pc_tree[pc_tree_index],
+                          4 << (2 * square_index));
+      x->pc_tree[pc_tree_index].block_size = square[square_index];
+      for (j = 0; j < 4; j++) {
+        x->pc_tree[pc_tree_index].split[j] = this_pc++;
+      }
+    }
+  }
+  x->pc_root = &x->pc_tree[tree_nodes-1];
+  x->pc_root[0].none.best_mode_index = 2;
+}
+
+void vp9_free_pc_tree(MACROBLOCK *m) {
+  const int tree_nodes = 64 + 16 + 4 + 1;
+  int i;
+
+  // Set up all 4x4 mode contexts
+  for (i = 0; i < 64; ++i)
+    free_mode_context(&m->leaf_tree[i]);
+
+  // Sets up all the leaf nodes in the tree.
+  for (i = 0; i < tree_nodes; i++) {
+    free_tree_contexts(&m->pc_tree[i]);
+  }
+  vpx_free(m->pc_tree);
+  m->pc_tree = 0;
+  vpx_free(m->leaf_tree);
+  m->leaf_tree = 0;
+}
diff --git a/vp9/encoder/vp9_context_tree.h b/vp9/encoder/vp9_context_tree.h
new file mode 100644
index 0000000..66a6f00
--- /dev/null
+++ b/vp9/encoder/vp9_context_tree.h
@@ -0,0 +1,19 @@
+/*
+ *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VP9_ENCODER_VP9_CONTEXT_TREE_H_
+#define VP9_ENCODER_VP9_CONTEXT_TREE_H_
+
+#include "vp9/encoder/vp9_encoder.h"
+
+void vp9_setup_pc_tree(VP9_COMMON *cm, MACROBLOCK *x);
+void vp9_free_pc_tree(MACROBLOCK *x);
+
+#endif /* VP9_ENCODER_VP9_CONTEXT_TREE_H_ */
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 0cc50f7..19aa592 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -48,41 +48,9 @@
 #define SPLIT_MV_ZBIN_BOOST  0
 #define INTRA_ZBIN_BOOST     0
 
-static INLINE uint8_t *get_sb_index(MACROBLOCK *x, BLOCK_SIZE subsize) {
-  switch (subsize) {
-    case BLOCK_64X64:
-    case BLOCK_64X32:
-    case BLOCK_32X64:
-    case BLOCK_32X32:
-      return &x->sb_index;
-    case BLOCK_32X16:
-    case BLOCK_16X32:
-    case BLOCK_16X16:
-      return &x->mb_index;
-    case BLOCK_16X8:
-    case BLOCK_8X16:
-    case BLOCK_8X8:
-      return &x->b_index;
-    case BLOCK_8X4:
-    case BLOCK_4X8:
-    case BLOCK_4X4:
-      return &x->ab_index;
-    default:
-      assert(0);
-      return NULL;
-  }
-}
-
 static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
-                              int mi_row, int mi_col, BLOCK_SIZE bsize);
-
-static void adjust_act_zbin(VP9_COMP *cpi, MACROBLOCK *x);
-
-// activity_avg must be positive, or flat regions could get a zero weight
-//  (infinite lambda), which confounds analysis.
-// This also avoids the need for divide by zero checks in
-//  vp9_activity_masking().
-#define ACTIVITY_AVG_MIN 64
+                              int mi_row, int mi_col, BLOCK_SIZE bsize,
+                              PICK_MODE_CONTEXT *ctx);
 
 // Motion vector component magnitude threshold for defining fast motion.
 #define FAST_MOTION_MV_THRESH 24
@@ -209,15 +177,11 @@
   MB_MODE_INFO *mbmi;
   const int mi_width = num_8x8_blocks_wide_lookup[bsize];
   const int mi_height = num_8x8_blocks_high_lookup[bsize];
-  const int mb_row = mi_row >> 1;
-  const int mb_col = mi_col >> 1;
-  const int idx_map = mb_row * cm->mb_cols + mb_col;
   const struct segmentation *const seg = &cm->seg;
 
   set_skip_context(xd, mi_row, mi_col);
 
   // Activity map pointer
-  x->mb_activity_ptr = &cpi->mb_activity_map[idx_map];
   x->in_active_map = check_active_map(cpi, x, mi_row, mi_col, bsize);
 
   set_modeinfo_offsets(cm, xd, mi_row, mi_col);
@@ -243,8 +207,8 @@
   vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col);
 
   // R/D setup.
-  x->rddiv = cpi->RDDIV;
-  x->rdmult = cpi->RDMULT;
+  x->rddiv = cpi->rd.RDDIV;
+  x->rdmult = cpi->rd.RDMULT;
 
   // Setup segment ID.
   if (seg->enabled) {
@@ -596,229 +560,12 @@
   return act < (8 << 12) ? MIN(act, 5 << 12) : act;
 }
 
-// Stub for alternative experimental activity measures.
-static unsigned int alt_activity_measure(MACROBLOCK *x, int use_dc_pred) {
-  return vp9_encode_intra(x, use_dc_pred);
-}
-
-// Measure the activity of the current macroblock
-// What we measure here is TBD so abstracted to this function
-#define ALT_ACT_MEASURE 1
-static unsigned int mb_activity_measure(MACROBLOCK *x, int mb_row, int mb_col) {
-  unsigned int mb_activity;
-
-  if (ALT_ACT_MEASURE) {
-    const int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row);
-
-    // Or use and alternative.
-    mb_activity = alt_activity_measure(x, use_dc_pred);
-  } else {
-    // Original activity measure from Tim T's code.
-    mb_activity = tt_activity_measure(x);
-  }
-
-  return MAX(mb_activity, ACTIVITY_AVG_MIN);
-}
-
-// Calculate an "average" mb activity value for the frame
-#define ACT_MEDIAN 0
-static void calc_av_activity(VP9_COMP *cpi, int64_t activity_sum) {
-#if ACT_MEDIAN
-  // Find median: Simple n^2 algorithm for experimentation
-  {
-    unsigned int median;
-    unsigned int i, j;
-    unsigned int *sortlist;
-    unsigned int tmp;
-
-    // Create a list to sort to
-    CHECK_MEM_ERROR(&cpi->common, sortlist, vpx_calloc(sizeof(unsigned int),
-                    cpi->common.MBs));
-
-    // Copy map to sort list
-    vpx_memcpy(sortlist, cpi->mb_activity_map,
-        sizeof(unsigned int) * cpi->common.MBs);
-
-    // Ripple each value down to its correct position
-    for (i = 1; i < cpi->common.MBs; i ++) {
-      for (j = i; j > 0; j --) {
-        if (sortlist[j] < sortlist[j - 1]) {
-          // Swap values
-          tmp = sortlist[j - 1];
-          sortlist[j - 1] = sortlist[j];
-          sortlist[j] = tmp;
-        } else {
-          break;
-        }
-      }
-    }
-
-    // Even number MBs so estimate median as mean of two either side.
-    median = (1 + sortlist[cpi->common.MBs >> 1] +
-        sortlist[(cpi->common.MBs >> 1) + 1]) >> 1;
-
-    cpi->activity_avg = median;
-
-    vpx_free(sortlist);
-  }
-#else
-  // Simple mean for now
-  cpi->activity_avg = (unsigned int) (activity_sum / cpi->common.MBs);
-#endif  // ACT_MEDIAN
-
-  if (cpi->activity_avg < ACTIVITY_AVG_MIN)
-    cpi->activity_avg = ACTIVITY_AVG_MIN;
-
-  // Experimental code: return fixed value normalized for several clips
-  if (ALT_ACT_MEASURE)
-    cpi->activity_avg = 100000;
-}
-
-#define USE_ACT_INDEX   0
-#define OUTPUT_NORM_ACT_STATS   0
-
-#if USE_ACT_INDEX
-// Calculate an activity index for each mb
-static void calc_activity_index(VP9_COMP *cpi, MACROBLOCK *x) {
-  VP9_COMMON *const cm = &cpi->common;
-  int mb_row, mb_col;
-
-  int64_t act;
-  int64_t a;
-  int64_t b;
-
-#if OUTPUT_NORM_ACT_STATS
-  FILE *f = fopen("norm_act.stt", "a");
-  fprintf(f, "\n%12d\n", cpi->activity_avg);
-#endif
-
-  // Reset pointers to start of activity map
-  x->mb_activity_ptr = cpi->mb_activity_map;
-
-  // Calculate normalized mb activity number.
-  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
-    // for each macroblock col in image
-    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
-      // Read activity from the map
-      act = *(x->mb_activity_ptr);
-
-      // Calculate a normalized activity number
-      a = act + 4 * cpi->activity_avg;
-      b = 4 * act + cpi->activity_avg;
-
-      if (b >= a)
-      *(x->activity_ptr) = (int)((b + (a >> 1)) / a) - 1;
-      else
-      *(x->activity_ptr) = 1 - (int)((a + (b >> 1)) / b);
-
-#if OUTPUT_NORM_ACT_STATS
-      fprintf(f, " %6d", *(x->mb_activity_ptr));
-#endif
-      // Increment activity map pointers
-      x->mb_activity_ptr++;
-    }
-
-#if OUTPUT_NORM_ACT_STATS
-    fprintf(f, "\n");
-#endif
-  }
-
-#if OUTPUT_NORM_ACT_STATS
-  fclose(f);
-#endif
-}
-#endif  // USE_ACT_INDEX
-
-// Loop through all MBs. Note activity of each, average activity and
-// calculate a normalized activity for each
-static void build_activity_map(VP9_COMP *cpi) {
-  MACROBLOCK *const x = &cpi->mb;
-  MACROBLOCKD *xd = &x->e_mbd;
-  VP9_COMMON *const cm = &cpi->common;
-
-#if ALT_ACT_MEASURE
-  YV12_BUFFER_CONFIG *new_yv12 = get_frame_new_buffer(cm);
-  int recon_yoffset;
-  int recon_y_stride = new_yv12->y_stride;
-#endif
-
-  int mb_row, mb_col;
-  unsigned int mb_activity;
-  int64_t activity_sum = 0;
-
-  x->mb_activity_ptr = cpi->mb_activity_map;
-
-  // for each macroblock row in image
-  for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
-#if ALT_ACT_MEASURE
-    // reset above block coeffs
-    xd->up_available = (mb_row != 0);
-    recon_yoffset = (mb_row * recon_y_stride * 16);
-#endif
-    // for each macroblock col in image
-    for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
-#if ALT_ACT_MEASURE
-      xd->plane[0].dst.buf = new_yv12->y_buffer + recon_yoffset;
-      xd->left_available = (mb_col != 0);
-      recon_yoffset += 16;
-#endif
-
-      // measure activity
-      mb_activity = mb_activity_measure(x, mb_row, mb_col);
-
-      // Keep frame sum
-      activity_sum += mb_activity;
-
-      // Store MB level activity details.
-      *x->mb_activity_ptr = mb_activity;
-
-      // Increment activity map pointer
-      x->mb_activity_ptr++;
-
-      // adjust to the next column of source macroblocks
-      x->plane[0].src.buf += 16;
-    }
-
-    // adjust to the next row of mbs
-    x->plane[0].src.buf += 16 * x->plane[0].src.stride - 16 * cm->mb_cols;
-  }
-
-  // Calculate an "average" MB activity
-  calc_av_activity(cpi, activity_sum);
-
-#if USE_ACT_INDEX
-  // Calculate an activity index number of each mb
-  calc_activity_index(cpi, x);
-#endif
-}
-
-// Macroblock activity masking
-static void activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
-#if USE_ACT_INDEX
-  x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2);
-  x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
-  x->errorperbit += (x->errorperbit == 0);
-#else
-  const int64_t act = *(x->mb_activity_ptr);
-
-  // Apply the masking to the RD multiplier.
-  const int64_t a = act + (2 * cpi->activity_avg);
-  const int64_t b = (2 * act) + cpi->activity_avg;
-
-  x->rdmult = (unsigned int) (((int64_t) x->rdmult * b + (a >> 1)) / a);
-  x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
-  x->errorperbit += (x->errorperbit == 0);
-#endif
-
-  // Activity based Zbin adjustment
-  adjust_act_zbin(cpi, x);
-}
-
 static void update_state(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
                          int mi_row, int mi_col, BLOCK_SIZE bsize,
                          int output_enabled) {
   int i, x_idx, y;
   VP9_COMMON *const cm = &cpi->common;
+  RD_OPT *const rd_opt = &cpi->rd;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
   struct macroblock_plane *const p = x->plane;
@@ -904,7 +651,7 @@
 
   if (!vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
     for (i = 0; i < TX_MODES; i++)
-      cpi->rd_tx_select_diff[i] += ctx->tx_rd_diff[i];
+      rd_opt->tx_select_diff[i] += ctx->tx_rd_diff[i];
   }
 
 #if CONFIG_INTERNAL_STATS
@@ -937,12 +684,12 @@
       }
     }
 
-    cpi->rd_comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
-    cpi->rd_comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff;
-    cpi->rd_comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff;
+    rd_opt->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff;
+    rd_opt->comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff;
+    rd_opt->comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff;
 
     for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
-      cpi->rd_filter_diff[i] += ctx->best_filter_diff[i];
+      rd_opt->filter_diff[i] += ctx->best_filter_diff[i];
   }
 }
 
@@ -967,7 +714,7 @@
                              int mi_row, int mi_col,
                              int *totalrate, int64_t *totaldist,
                              BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
-                             int64_t best_rd) {
+                             int64_t best_rd, int block) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -984,10 +731,13 @@
   // Use the lower precision, but faster, 32x32 fdct for mode selection.
   x->use_lp32x32fdct = 1;
 
+  // TODO(JBB): Most other places in the code instead of calling the function
+  // and then checking if its not the first 8x8 we put the check in the
+  // calling function.  Do that here.
   if (bsize < BLOCK_8X8) {
     // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
     // there is nothing to be done.
-    if (x->ab_index != 0) {
+    if (block != 0) {
       *totalrate = 0;
       *totaldist = 0;
       return;
@@ -1014,8 +764,6 @@
 
   // Save rdmult before it might be changed, so it can be restored later.
   orig_rdmult = x->rdmult;
-  if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
-    activity_masking(cpi, x);
 
   if (aq_mode == VARIANCE_AQ) {
     const int energy = bsize <= BLOCK_16X16 ? x->mb_energy
@@ -1112,22 +860,6 @@
   }
 }
 
-static BLOCK_SIZE *get_sb_partitioning(MACROBLOCK *x, BLOCK_SIZE bsize) {
-  switch (bsize) {
-    case BLOCK_64X64:
-      return &x->sb64_partitioning;
-    case BLOCK_32X32:
-      return &x->sb_partitioning[x->sb_index];
-    case BLOCK_16X16:
-      return &x->mb_partitioning[x->sb_index][x->mb_index];
-    case BLOCK_8X8:
-      return &x->b_partitioning[x->sb_index][x->mb_index][x->b_index];
-    default:
-      assert(0);
-      return NULL;
-  }
-}
-
 static void restore_context(VP9_COMP *cpi, int mi_row, int mi_col,
                             ENTROPY_CONTEXT a[16 * MAX_MB_PLANE],
                             ENTROPY_CONTEXT l[16 * MAX_MB_PLANE],
@@ -1193,19 +925,12 @@
 
 static void encode_b(VP9_COMP *cpi, const TileInfo *const tile,
                      TOKENEXTRA **tp, int mi_row, int mi_col,
-                     int output_enabled, BLOCK_SIZE bsize) {
-  MACROBLOCK *const x = &cpi->mb;
+                     int output_enabled, BLOCK_SIZE bsize,
+                     PICK_MODE_CONTEXT *ctx) {
 
-  if (bsize < BLOCK_8X8) {
-    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
-    // there is nothing to be done.
-    if (x->ab_index > 0)
-      return;
-  }
   set_offsets(cpi, tile, mi_row, mi_col, bsize);
-  update_state(cpi, get_block_context(x, bsize), mi_row, mi_col, bsize,
-               output_enabled);
-  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize);
+  update_state(cpi, ctx, mi_row, mi_col, bsize, output_enabled);
+  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize, ctx);
 
   if (output_enabled) {
     update_stats(cpi);
@@ -1217,7 +942,8 @@
 
 static void encode_sb(VP9_COMP *cpi, const TileInfo *const tile,
                       TOKENEXTRA **tp, int mi_row, int mi_col,
-                      int output_enabled, BLOCK_SIZE bsize) {
+                      int output_enabled, BLOCK_SIZE bsize,
+                      PC_TREE *pc_tree) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -1225,61 +951,58 @@
   const int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
   int ctx;
   PARTITION_TYPE partition;
-  BLOCK_SIZE subsize;
+  BLOCK_SIZE subsize = bsize;
 
   if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
     return;
 
   if (bsize >= BLOCK_8X8) {
     ctx = partition_plane_context(xd, mi_row, mi_col, bsize);
-    subsize = *get_sb_partitioning(x, bsize);
+    subsize = get_subsize(bsize, pc_tree->partitioning);
   } else {
     ctx = 0;
     subsize = BLOCK_4X4;
   }
 
   partition = partition_lookup[bsl][subsize];
+  if (output_enabled && bsize != BLOCK_4X4)
+    cm->counts.partition[ctx][partition]++;
 
   switch (partition) {
     case PARTITION_NONE:
-      if (output_enabled && bsize >= BLOCK_8X8)
-        cm->counts.partition[ctx][PARTITION_NONE]++;
-      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
+      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+               &pc_tree->none);
       break;
     case PARTITION_VERT:
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_VERT]++;
-      *get_sb_index(x, subsize) = 0;
-      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      if (mi_col + hbs < cm->mi_cols) {
-        *get_sb_index(x, subsize) = 1;
-        encode_b(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize);
+      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+               &pc_tree->vertical[0]);
+      if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) {
+        encode_b(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize,
+                 &pc_tree->vertical[1]);
       }
       break;
     case PARTITION_HORZ:
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_HORZ]++;
-      *get_sb_index(x, subsize) = 0;
-      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      if (mi_row + hbs < cm->mi_rows) {
-        *get_sb_index(x, subsize) = 1;
-        encode_b(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize);
+      encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+               &pc_tree->horizontal[0]);
+      if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) {
+        encode_b(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize,
+                 &pc_tree->horizontal[1]);
       }
       break;
     case PARTITION_SPLIT:
-      subsize = get_subsize(bsize, PARTITION_SPLIT);
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_SPLIT]++;
-
-      *get_sb_index(x, subsize) = 0;
-      encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      *get_sb_index(x, subsize) = 1;
-      encode_sb(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize);
-      *get_sb_index(x, subsize) = 2;
-      encode_sb(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize);
-      *get_sb_index(x, subsize) = 3;
-      encode_sb(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled,
-                subsize);
+      if (bsize == BLOCK_8X8) {
+        encode_b(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                 pc_tree->leaf_split[0]);
+      } else {
+        encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                  pc_tree->split[0]);
+        encode_sb(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled, subsize,
+                  pc_tree->split[1]);
+        encode_sb(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled, subsize,
+                  pc_tree->split[2]);
+        encode_sb(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled,
+                  subsize, pc_tree->split[3]);
+      }
       break;
     default:
       assert("Invalid partition type.");
@@ -1309,6 +1032,22 @@
   return bsize;
 }
 
+static void set_partial_b64x64_partition(MODE_INFO *mi, int mis,
+    int bh_in, int bw_in, int row8x8_remaining, int col8x8_remaining,
+    BLOCK_SIZE bsize, MODE_INFO **mi_8x8) {
+  int bh = bh_in;
+  int r, c;
+  for (r = 0; r < MI_BLOCK_SIZE; r += bh) {
+    int bw = bw_in;
+    for (c = 0; c < MI_BLOCK_SIZE; c += bw) {
+      const int index = r * mis + c;
+      mi_8x8[index] = mi + index;
+      mi_8x8[index]->mbmi.sb_type = find_partition_size(bsize,
+          row8x8_remaining - r, col8x8_remaining - c, &bh, &bw);
+    }
+  }
+}
+
 // This function attempts to set all mode info entries in a given SB64
 // to the same block partition size.
 // However, at the bottom and right borders of the image the requested size
@@ -1319,8 +1058,8 @@
                                    BLOCK_SIZE bsize) {
   VP9_COMMON *const cm = &cpi->common;
   const int mis = cm->mi_stride;
-  int row8x8_remaining = tile->mi_row_end - mi_row;
-  int col8x8_remaining = tile->mi_col_end - mi_col;
+  const int row8x8_remaining = tile->mi_row_end - mi_row;
+  const int col8x8_remaining = tile->mi_col_end - mi_col;
   int block_row, block_col;
   MODE_INFO *mi_upper_left = cm->mi + mi_row * mis + mi_col;
   int bh = num_8x8_blocks_high_lookup[bsize];
@@ -1340,15 +1079,25 @@
     }
   } else {
     // Else this is a partial SB64.
-    for (block_row = 0; block_row < MI_BLOCK_SIZE; block_row += bh) {
-      for (block_col = 0; block_col < MI_BLOCK_SIZE; block_col += bw) {
-        int index = block_row * mis + block_col;
-        // Find a partition size that fits
-        bsize = find_partition_size(bsize,
-                                    (row8x8_remaining - block_row),
-                                    (col8x8_remaining - block_col), &bh, &bw);
-        mi_8x8[index] = mi_upper_left + index;
-        mi_8x8[index]->mbmi.sb_type = bsize;
+    set_partial_b64x64_partition(mi_upper_left, mis, bh, bw, row8x8_remaining,
+        col8x8_remaining, bsize, mi_8x8);
+  }
+}
+
+static void copy_partitioning(VP9_COMMON *cm, MODE_INFO **mi_8x8,
+  MODE_INFO **prev_mi_8x8) {
+  const int mis = cm->mi_stride;
+  int block_row, block_col;
+
+  for (block_row = 0; block_row < 8; ++block_row) {
+    for (block_col = 0; block_col < 8; ++block_col) {
+      MODE_INFO *const prev_mi = prev_mi_8x8[block_row * mis + block_col];
+      const BLOCK_SIZE sb_type = prev_mi ? prev_mi->mbmi.sb_type : 0;
+
+      if (prev_mi) {
+        const ptrdiff_t offset = prev_mi - cm->prev_mi;
+        mi_8x8[block_row * mis + block_col] = cm->mi + offset;
+        mi_8x8[block_row * mis + block_col]->mbmi.sb_type = sb_type;
       }
     }
   }
@@ -1403,38 +1152,10 @@
     }
   } else {
     // Else this is a partial SB64, copy previous partition.
-    for (block_row = 0; block_row < 8; ++block_row) {
-      for (block_col = 0; block_col < 8; ++block_col) {
-        MODE_INFO *const prev_mi = prev_mi_8x8[block_row * mis + block_col];
-        const BLOCK_SIZE sb_type = prev_mi ? prev_mi->mbmi.sb_type : 0;
-        if (prev_mi) {
-          const ptrdiff_t offset = prev_mi - cm->prev_mi;
-          mi_8x8[block_row * mis + block_col] = cm->mi + offset;
-          mi_8x8[block_row * mis + block_col]->mbmi.sb_type = sb_type;
-        }
-      }
-    }
+    copy_partitioning(cm, mi_8x8, prev_mi_8x8);
   }
 }
 
-static void copy_partitioning(VP9_COMMON *cm, MODE_INFO **mi_8x8,
-                              MODE_INFO **prev_mi_8x8) {
-  const int mis = cm->mi_stride;
-  int block_row, block_col;
-
-  for (block_row = 0; block_row < 8; ++block_row) {
-    for (block_col = 0; block_col < 8; ++block_col) {
-      MODE_INFO *const prev_mi = prev_mi_8x8[block_row * mis + block_col];
-      const BLOCK_SIZE sb_type = prev_mi ? prev_mi->mbmi.sb_type : 0;
-
-      if (prev_mi) {
-        const ptrdiff_t offset = prev_mi - cm->prev_mi;
-        mi_8x8[block_row * mis + block_col] = cm->mi + offset;
-        mi_8x8[block_row * mis + block_col]->mbmi.sb_type = sb_type;
-      }
-    }
-  }
-}
 
 const struct {
   int row;
@@ -1455,13 +1176,14 @@
                                            MODE_INFO **mi_8x8,
                                            int mi_row, int mi_col) {
   VP9_COMMON *const cm = &cpi->common;
-  MACROBLOCK *x = &cpi->mb;
+  MACROBLOCK *const x = &cpi->mb;
   const int mis = cm->mi_stride;
-  int row8x8_remaining = tile->mi_row_end - mi_row;
-  int col8x8_remaining = tile->mi_col_end - mi_col;
-  int r, c;
+  const int row8x8_remaining = tile->mi_row_end - mi_row;
+  const int col8x8_remaining = tile->mi_col_end - mi_col;
   MODE_INFO *mi_upper_left = cm->mi + mi_row * mis + mi_col;
 
+  vp9_setup_src_planes(x, cpi->Source, mi_row, mi_col);
+
   assert((row8x8_remaining > 0) && (col8x8_remaining > 0));
 
   // In-image SB64
@@ -1473,8 +1195,8 @@
     const int pre_offset = (mi_row * MI_SIZE) * pre_stride +
                            (mi_col * MI_SIZE);
     const uint8_t *pre_src = cpi->Last_Source->y_buffer + pre_offset;
-    const int thr_32x32 = cpi->sf.source_var_thresh;
-    const int thr_64x64 = thr_32x32 << 1;
+    const unsigned int thr_32x32 = cpi->sf.source_var_thresh;
+    const unsigned int thr_64x64 = thr_32x32 << 1;
     int i, j;
     int index;
     diff d32[4];
@@ -1537,24 +1259,51 @@
       }
     }
   } else {   // partial in-image SB64
-    BLOCK_SIZE bsize = BLOCK_16X16;
-    int bh = num_8x8_blocks_high_lookup[bsize];
-    int bw = num_8x8_blocks_wide_lookup[bsize];
-
-    for (r = 0; r < MI_BLOCK_SIZE; r += bh) {
-      for (c = 0; c < MI_BLOCK_SIZE; c += bw) {
-        int index = r * mis + c;
-        // Find a partition size that fits
-        bsize = find_partition_size(bsize,
-                                    (row8x8_remaining - r),
-                                    (col8x8_remaining - c), &bh, &bw);
-        mi_8x8[index] = mi_upper_left + index;
-        mi_8x8[index]->mbmi.sb_type = bsize;
-      }
-    }
+    int bh = num_8x8_blocks_high_lookup[BLOCK_16X16];
+    int bw = num_8x8_blocks_wide_lookup[BLOCK_16X16];
+    set_partial_b64x64_partition(mi_upper_left, mis, bh, bw,
+        row8x8_remaining, col8x8_remaining, BLOCK_16X16, mi_8x8);
   }
 }
 
+static int is_background(VP9_COMP *cpi, const TileInfo *const tile,
+                         int mi_row, int mi_col) {
+  MACROBLOCK *x = &cpi->mb;
+  uint8_t *src, *pre;
+  int src_stride, pre_stride;
+
+  const int row8x8_remaining = tile->mi_row_end - mi_row;
+  const int col8x8_remaining = tile->mi_col_end - mi_col;
+
+  int this_sad = 0;
+  int threshold = 0;
+
+  // This assumes the input source frames are of the same dimension.
+  src_stride = cpi->Source->y_stride;
+  src = cpi->Source->y_buffer + (mi_row * MI_SIZE) * src_stride +
+            (mi_col * MI_SIZE);
+  pre_stride = cpi->Last_Source->y_stride;
+  pre = cpi->Last_Source->y_buffer + (mi_row * MI_SIZE) * pre_stride +
+          (mi_col * MI_SIZE);
+
+  if (row8x8_remaining >= MI_BLOCK_SIZE &&
+      col8x8_remaining >= MI_BLOCK_SIZE) {
+    this_sad = cpi->fn_ptr[BLOCK_64X64].sdf(src, src_stride,
+                                            pre, pre_stride, 0x7fffffff);
+    threshold = (1 << 12);
+  } else {
+    int r, c;
+    for (r = 0; r < row8x8_remaining; r += 2)
+      for (c = 0; c < col8x8_remaining; c += 2)
+        this_sad += cpi->fn_ptr[BLOCK_16X16].sdf(src, src_stride, pre,
+                                                 pre_stride, 0x7fffffff);
+    threshold = (row8x8_remaining * col8x8_remaining) << 6;
+  }
+
+  x->in_static_area = (this_sad < 2 * threshold);
+  return x->in_static_area;
+}
+
 static int sb_has_motion(const VP9_COMMON *cm, MODE_INFO **prev_mi_8x8) {
   const int mis = cm->mi_stride;
   int block_row, block_col;
@@ -1606,20 +1355,14 @@
 
 static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile,
                         TOKENEXTRA **tp, int mi_row, int mi_col,
-                        int output_enabled, BLOCK_SIZE bsize) {
-  MACROBLOCK *const x = &cpi->mb;
+                     int output_enabled, BLOCK_SIZE bsize,
+                     PICK_MODE_CONTEXT *ctx) {
 
-  if (bsize < BLOCK_8X8) {
-    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
-    // there is nothing to be done.
-    if (x->ab_index > 0)
-      return;
-  }
 
   set_offsets(cpi, tile, mi_row, mi_col, bsize);
-  update_state_rt(cpi, get_block_context(x, bsize), mi_row, mi_col, bsize);
+  update_state_rt(cpi, ctx, mi_row, mi_col, bsize);
 
-  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize);
+  encode_superblock(cpi, tp, output_enabled, mi_row, mi_col, bsize, ctx);
   update_stats(cpi);
 
   (*tp)->token = EOSB_TOKEN;
@@ -1628,7 +1371,8 @@
 
 static void encode_sb_rt(VP9_COMP *cpi, const TileInfo *const tile,
                          TOKENEXTRA **tp, int mi_row, int mi_col,
-                         int output_enabled, BLOCK_SIZE bsize) {
+                         int output_enabled, BLOCK_SIZE bsize,
+                         PC_TREE *pc_tree) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -1653,51 +1397,40 @@
   }
 
   partition = partition_lookup[bsl][subsize];
+  if (output_enabled && bsize != BLOCK_4X4)
+    cm->counts.partition[ctx][partition]++;
 
   switch (partition) {
     case PARTITION_NONE:
-      if (output_enabled && bsize >= BLOCK_8X8)
-        cm->counts.partition[ctx][PARTITION_NONE]++;
-      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
+      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                  &pc_tree->none);
       break;
     case PARTITION_VERT:
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_VERT]++;
-      *get_sb_index(x, subsize) = 0;
-      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      if (mi_col + hbs < cm->mi_cols) {
-        *get_sb_index(x, subsize) = 1;
+      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                  &pc_tree->vertical[0]);
+      if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) {
         encode_b_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled,
-                    subsize);
+                    subsize, &pc_tree->vertical[1]);
       }
       break;
     case PARTITION_HORZ:
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_HORZ]++;
-      *get_sb_index(x, subsize) = 0;
-      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      if (mi_row + hbs < cm->mi_rows) {
-        *get_sb_index(x, subsize) = 1;
+      encode_b_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                  &pc_tree->horizontal[0]);
+      if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) {
         encode_b_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled,
-                    subsize);
+                    subsize, &pc_tree->horizontal[1]);
       }
       break;
     case PARTITION_SPLIT:
       subsize = get_subsize(bsize, PARTITION_SPLIT);
-      if (output_enabled)
-        cm->counts.partition[ctx][PARTITION_SPLIT]++;
-
-      *get_sb_index(x, subsize) = 0;
-      encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize);
-      *get_sb_index(x, subsize) = 1;
+      encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, subsize,
+                   pc_tree->split[0]);
       encode_sb_rt(cpi, tile, tp, mi_row, mi_col + hbs, output_enabled,
-                   subsize);
-      *get_sb_index(x, subsize) = 2;
+                   subsize, pc_tree->split[1]);
       encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col, output_enabled,
-                   subsize);
-      *get_sb_index(x, subsize) = 3;
+                   subsize, pc_tree->split[2]);
       encode_sb_rt(cpi, tile, tp, mi_row + hbs, mi_col + hbs, output_enabled,
-                   subsize);
+                   subsize, pc_tree->split[3]);
       break;
     default:
       assert("Invalid partition type.");
@@ -1712,7 +1445,8 @@
                              MODE_INFO **mi_8x8,
                              TOKENEXTRA **tp, int mi_row, int mi_col,
                              BLOCK_SIZE bsize, int *rate, int64_t *dist,
-                             int do_recon) {
+                             int do_recon, PC_TREE *pc_tree,
+                             int block) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -1738,6 +1472,7 @@
   int splits_below = 0;
   BLOCK_SIZE bs_type = mi_8x8[0]->mbmi.sb_type;
   int do_partition_search = 1;
+  PICK_MODE_CONTEXT *ctx = &pc_tree->none;
 
   if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
     return;
@@ -1748,17 +1483,7 @@
   partition = partition_lookup[bsl][bs_type];
   subsize = get_subsize(bsize, partition);
 
-  if (bsize < BLOCK_8X8) {
-    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
-    // there is nothing to be done.
-    if (x->ab_index != 0) {
-      *rate = 0;
-      *dist = 0;
-      return;
-    }
-  } else {
-    *(get_sb_partitioning(x, bsize)) = subsize;
-  }
+  pc_tree->partitioning = partition;
   save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
 
   if (bsize == BLOCK_16X16) {
@@ -1772,7 +1497,7 @@
     do_partition_search = 0;
     if (mi_row + (mi_step >> 1) < cm->mi_rows &&
         mi_col + (mi_step >> 1) < cm->mi_cols) {
-      *(get_sb_partitioning(x, bsize)) = bsize;
+      pc_tree->partitioning = PARTITION_NONE;
       bs_type = mi_8x8[0]->mbmi.sb_type = bsize;
       subsize = bsize;
       partition = PARTITION_NONE;
@@ -1799,9 +1524,9 @@
     if (partition != PARTITION_NONE && !splits_below &&
         mi_row + (mi_step >> 1) < cm->mi_rows &&
         mi_col + (mi_step >> 1) < cm->mi_cols) {
-      *(get_sb_partitioning(x, bsize)) = bsize;
+      pc_tree->partitioning = PARTITION_NONE;
       rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &none_rate, &none_dist, bsize,
-                       get_block_context(x, bsize), INT64_MAX);
+                       ctx, INT64_MAX, 0);
 
       pl = partition_plane_context(xd, mi_row, mi_col, bsize);
 
@@ -1812,31 +1537,28 @@
 
       restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
       mi_8x8[0]->mbmi.sb_type = bs_type;
-      *(get_sb_partitioning(x, bsize)) = subsize;
+      pc_tree->partitioning = partition;
     }
   }
 
   switch (partition) {
     case PARTITION_NONE:
       rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
-                       &last_part_dist, bsize,
-                       get_block_context(x, bsize), INT64_MAX);
+                       &last_part_dist, bsize, ctx, INT64_MAX, 0);
       break;
     case PARTITION_HORZ:
-      *get_sb_index(x, subsize) = 0;
       rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
-                       &last_part_dist, subsize,
-                       get_block_context(x, subsize), INT64_MAX);
+                       &last_part_dist, subsize, &pc_tree->horizontal[0],
+                       INT64_MAX, 0);
       if (last_part_rate != INT_MAX &&
           bsize >= BLOCK_8X8 && mi_row + (mi_step >> 1) < cm->mi_rows) {
         int rt = 0;
         int64_t dt = 0;
-        update_state(cpi, get_block_context(x, subsize), mi_row, mi_col,
-                     subsize, 0);
-        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
-        *get_sb_index(x, subsize) = 1;
+        PICK_MODE_CONTEXT *ctx = &pc_tree->horizontal[0];
+        update_state(cpi, ctx, mi_row, mi_col, subsize, 0);
+        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx);
         rd_pick_sb_modes(cpi, tile, mi_row + (mi_step >> 1), mi_col, &rt, &dt,
-                         subsize, get_block_context(x, subsize), INT64_MAX);
+                         subsize, &pc_tree->horizontal[1], INT64_MAX, 1);
         if (rt == INT_MAX || dt == INT64_MAX) {
           last_part_rate = INT_MAX;
           last_part_dist = INT64_MAX;
@@ -1848,20 +1570,19 @@
       }
       break;
     case PARTITION_VERT:
-      *get_sb_index(x, subsize) = 0;
       rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
-                       &last_part_dist, subsize,
-                       get_block_context(x, subsize), INT64_MAX);
+                       &last_part_dist, subsize, &pc_tree->vertical[0],
+                       INT64_MAX, 0);
       if (last_part_rate != INT_MAX &&
           bsize >= BLOCK_8X8 && mi_col + (mi_step >> 1) < cm->mi_cols) {
         int rt = 0;
         int64_t dt = 0;
-        update_state(cpi, get_block_context(x, subsize), mi_row, mi_col,
-                     subsize, 0);
-        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
-        *get_sb_index(x, subsize) = 1;
+        PICK_MODE_CONTEXT *ctx = &pc_tree->vertical[0];
+        update_state(cpi, ctx, mi_row, mi_col, subsize, 0);
+        encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx);
         rd_pick_sb_modes(cpi, tile, mi_row, mi_col + (mi_step >> 1), &rt, &dt,
-                         subsize, get_block_context(x, subsize), INT64_MAX);
+                         subsize, &pc_tree->vertical[bsize > BLOCK_8X8],
+                         INT64_MAX, 1);
         if (rt == INT_MAX || dt == INT64_MAX) {
           last_part_rate = INT_MAX;
           last_part_dist = INT64_MAX;
@@ -1872,7 +1593,12 @@
       }
       break;
     case PARTITION_SPLIT:
-      // Split partition.
+      if (bsize == BLOCK_8X8) {
+        rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &last_part_rate,
+                         &last_part_dist, subsize, pc_tree->leaf_split[0],
+                         INT64_MAX, 0);
+        break;
+      }
       last_part_rate = 0;
       last_part_dist = 0;
       for (i = 0; i < 4; i++) {
@@ -1885,11 +1611,9 @@
         if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols))
           continue;
 
-        *get_sb_index(x, subsize) = i;
-
         rd_use_partition(cpi, tile, mi_8x8 + jj * bss * mis + ii * bss, tp,
                          mi_row + y_idx, mi_col + x_idx, subsize, &rt, &dt,
-                         i != 3);
+                         i != 3, pc_tree->split[i], i);
         if (rt == INT_MAX || dt == INT64_MAX) {
           last_part_rate = INT_MAX;
           last_part_dist = INT64_MAX;
@@ -1921,6 +1645,7 @@
     chosen_rate = 0;
     chosen_dist = 0;
     restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
+    pc_tree->partitioning = PARTITION_SPLIT;
 
     // Split partition.
     for (i = 0; i < 4; i++) {
@@ -1934,15 +1659,11 @@
       if ((mi_row + y_idx >= cm->mi_rows) || (mi_col + x_idx >= cm->mi_cols))
         continue;
 
-      *get_sb_index(x, split_subsize) = i;
-      *get_sb_partitioning(x, bsize) = split_subsize;
-      *get_sb_partitioning(x, split_subsize) = split_subsize;
-
       save_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
-
+      pc_tree->split[i]->partitioning = PARTITION_NONE;
       rd_pick_sb_modes(cpi, tile, mi_row + y_idx, mi_col + x_idx, &rt, &dt,
-                       split_subsize, get_block_context(x, split_subsize),
-                       INT64_MAX);
+                       split_subsize, &pc_tree->split[i]->none,
+                       INT64_MAX, i);
 
       restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
 
@@ -1957,7 +1678,7 @@
 
       if (i != 3)
         encode_sb(cpi, tile, tp,  mi_row + y_idx, mi_col + x_idx, 0,
-                  split_subsize);
+                  split_subsize, pc_tree->split[i]);
 
       pl = partition_plane_context(xd, mi_row + y_idx, mi_col + x_idx,
                                    split_subsize);
@@ -1970,19 +1691,19 @@
     }
   }
 
-  // If last_part is better set the partitioning to that...
+  // If last_part is better set the partitioning to that.
   if (last_part_rd < chosen_rd) {
     mi_8x8[0]->mbmi.sb_type = bsize;
     if (bsize >= BLOCK_8X8)
-      *(get_sb_partitioning(x, bsize)) = subsize;
+      pc_tree->partitioning = partition;
     chosen_rate = last_part_rate;
     chosen_dist = last_part_dist;
     chosen_rd = last_part_rd;
   }
-  // If none was better set the partitioning to that...
+  // If none was better set the partitioning to that.
   if (none_rd < chosen_rd) {
     if (bsize >= BLOCK_8X8)
-      *(get_sb_partitioning(x, bsize)) = bsize;
+      pc_tree->partitioning = PARTITION_NONE;
     chosen_rate = none_rate;
     chosen_dist = none_dist;
   }
@@ -2008,8 +1729,8 @@
     if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
       vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
                                               chosen_rate, chosen_dist);
-
-    encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize);
+    encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize,
+              pc_tree);
   }
 
   *rate = chosen_rate;
@@ -2153,7 +1874,8 @@
 static void rd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
                               TOKENEXTRA **tp, int mi_row,
                               int mi_col, BLOCK_SIZE bsize, int *rate,
-                              int64_t *dist, int do_recon, int64_t best_rd) {
+                              int64_t *dist, int do_recon, int64_t best_rd,
+                              PC_TREE *pc_tree, int block) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -2161,7 +1883,7 @@
   ENTROPY_CONTEXT l[16 * MAX_MB_PLANE], a[16 * MAX_MB_PLANE];
   PARTITION_CONTEXT sl[8], sa[8];
   TOKENEXTRA *tp_orig = *tp;
-  PICK_MODE_CONTEXT *ctx = get_block_context(x, bsize);
+  PICK_MODE_CONTEXT *ctx = &pc_tree->none;
   int i, pl;
   BLOCK_SIZE subsize;
   int this_rate, sum_rate = 0, best_rate = INT_MAX;
@@ -2182,15 +1904,6 @@
                                bsize >= BLOCK_8X8;
   (void) *tp_orig;
 
-  if (bsize < BLOCK_8X8) {
-    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
-    // there is nothing to be done.
-    if (x->ab_index != 0) {
-      *rate = 0;
-      *dist = 0;
-      return;
-    }
-  }
   assert(num_8x8_blocks_wide_lookup[bsize] ==
              num_8x8_blocks_high_lookup[bsize]);
 
@@ -2200,7 +1913,6 @@
   } else {
     x->in_active_map = check_active_map(cpi, x, mi_row, mi_col, bsize);
   }
-
   // Determine partition types in search according to the speed features.
   // The threshold set here has to be of square block size.
   if (cpi->sf.auto_min_max_partition_size) {
@@ -2237,7 +1949,7 @@
   // PARTITION_NONE
   if (partition_none_allowed) {
     rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &this_rate, &this_dist, bsize,
-                     ctx, best_rd);
+                     ctx, best_rd, 0);
     if (this_rate != INT_MAX) {
       if (bsize >= BLOCK_8X8) {
         pl = partition_plane_context(xd, mi_row, mi_col, bsize);
@@ -2252,7 +1964,7 @@
         best_dist = this_dist;
         best_rd = sum_rd;
         if (bsize >= BLOCK_8X8)
-          *(get_sb_partitioning(x, bsize)) = bsize;
+          pc_tree->partitioning = PARTITION_NONE;
 
         // Adjust threshold according to partition size.
         stop_thresh >>= 8 - (b_width_log2_lookup[bsize] +
@@ -2284,31 +1996,49 @@
   // the starting point of motion search in the following partition type check.
   if (do_split) {
     subsize = get_subsize(bsize, PARTITION_SPLIT);
-    for (i = 0; i < 4 && sum_rd < best_rd; ++i) {
+    if (bsize == BLOCK_8X8) {
+      i = 4;
+      if (cpi->sf.adaptive_pred_interp_filter && partition_none_allowed)
+        pc_tree->leaf_split[0]->pred_interp_filter =
+            ctx->mic.mbmi.interp_filter;
+      rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
+                       pc_tree->leaf_split[0], best_rd, 0);
+      if (sum_rate == INT_MAX) {
+        sum_rd = INT64_MAX;
+      } else {
+        sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
+        if (sum_rd < best_rd) {
+          update_state(cpi, pc_tree->leaf_split[0], mi_row, mi_col, subsize, 0);
+          encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize,
+                            pc_tree->leaf_split[0]);
+          update_partition_context(xd, mi_row, mi_col, subsize, bsize);
+        }
+      }
+    } else {
+      for (i = 0; i < 4 && sum_rd < best_rd; ++i) {
       const int x_idx = (i & 1) * mi_step;
       const int y_idx = (i >> 1) * mi_step;
 
-      if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
-        continue;
+        if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
+          continue;
 
-      *get_sb_index(x, subsize) = i;
-      if (cpi->sf.adaptive_motion_search)
-        load_pred_mv(x, ctx);
-      if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
-          partition_none_allowed)
-        get_block_context(x, subsize)->pred_interp_filter =
-            ctx->mic.mbmi.interp_filter;
-      rd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx, subsize,
-                        &this_rate, &this_dist, i != 3, best_rd - sum_rd);
+        if (cpi->sf.adaptive_motion_search)
+          load_pred_mv(x, ctx);
 
-      if (this_rate == INT_MAX) {
-        sum_rd = INT64_MAX;
-      } else {
-        sum_rate += this_rate;
-        sum_dist += this_dist;
-        sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
+        rd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx,
+                          subsize, &this_rate, &this_dist, i != 3,
+                          best_rd - sum_rd, pc_tree->split[i], i);
+
+        if (this_rate == INT_MAX) {
+          sum_rd = INT64_MAX;
+        } else {
+          sum_rate += this_rate;
+          sum_dist += this_dist;
+          sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
+        }
       }
     }
+
     if (sum_rd < best_rd && i == 4) {
       pl = partition_plane_context(xd, mi_row, mi_col, bsize);
       sum_rate += x->partition_cost[pl][PARTITION_SPLIT];
@@ -2317,7 +2047,7 @@
         best_rate = sum_rate;
         best_dist = sum_dist;
         best_rd = sum_rd;
-        *(get_sb_partitioning(x, bsize)) = subsize;
+        pc_tree->partitioning = PARTITION_SPLIT;
       }
     } else {
       // skip rectangular partition test when larger block size
@@ -2331,32 +2061,30 @@
   // PARTITION_HORZ
   if (partition_horz_allowed && do_rect) {
     subsize = get_subsize(bsize, PARTITION_HORZ);
-    *get_sb_index(x, subsize) = 0;
     if (cpi->sf.adaptive_motion_search)
       load_pred_mv(x, ctx);
     if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
         partition_none_allowed)
-      get_block_context(x, subsize)->pred_interp_filter =
+      pc_tree->horizontal[0].pred_interp_filter =
           ctx->mic.mbmi.interp_filter;
     rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
-                     get_block_context(x, subsize), best_rd);
+                     &pc_tree->horizontal[0], best_rd, 0);
     sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
 
     if (sum_rd < best_rd && mi_row + mi_step < cm->mi_rows) {
-      update_state(cpi, get_block_context(x, subsize), mi_row, mi_col,
-                   subsize, 0);
-      encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
+      PICK_MODE_CONTEXT *ctx = &pc_tree->horizontal[0];
+      update_state(cpi, ctx, mi_row, mi_col, subsize, 0);
+      encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize, ctx);
 
-      *get_sb_index(x, subsize) = 1;
       if (cpi->sf.adaptive_motion_search)
         load_pred_mv(x, ctx);
       if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
           partition_none_allowed)
-        get_block_context(x, subsize)->pred_interp_filter =
+        pc_tree->horizontal[1].pred_interp_filter =
             ctx->mic.mbmi.interp_filter;
       rd_pick_sb_modes(cpi, tile, mi_row + mi_step, mi_col, &this_rate,
-                       &this_dist, subsize, get_block_context(x, subsize),
-                       best_rd - sum_rd);
+                       &this_dist, subsize, &pc_tree->horizontal[1],
+                       best_rd - sum_rd, 1);
       if (this_rate == INT_MAX) {
         sum_rd = INT64_MAX;
       } else {
@@ -2373,41 +2101,39 @@
         best_rd = sum_rd;
         best_rate = sum_rate;
         best_dist = sum_dist;
-        *(get_sb_partitioning(x, bsize)) = subsize;
+        pc_tree->partitioning = PARTITION_HORZ;
       }
     }
     restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
   }
-
   // PARTITION_VERT
   if (partition_vert_allowed && do_rect) {
     subsize = get_subsize(bsize, PARTITION_VERT);
 
-    *get_sb_index(x, subsize) = 0;
     if (cpi->sf.adaptive_motion_search)
       load_pred_mv(x, ctx);
     if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
         partition_none_allowed)
-      get_block_context(x, subsize)->pred_interp_filter =
+      pc_tree->vertical[0].pred_interp_filter =
           ctx->mic.mbmi.interp_filter;
     rd_pick_sb_modes(cpi, tile, mi_row, mi_col, &sum_rate, &sum_dist, subsize,
-                     get_block_context(x, subsize), best_rd);
+                     &pc_tree->vertical[0], best_rd, 0);
     sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
     if (sum_rd < best_rd && mi_col + mi_step < cm->mi_cols) {
-      update_state(cpi, get_block_context(x, subsize), mi_row, mi_col,
-                   subsize, 0);
-      encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize);
+      update_state(cpi, &pc_tree->vertical[0], mi_row, mi_col, subsize, 0);
+      encode_superblock(cpi, tp, 0, mi_row, mi_col, subsize,
+                        &pc_tree->vertical[0]);
 
-      *get_sb_index(x, subsize) = 1;
       if (cpi->sf.adaptive_motion_search)
         load_pred_mv(x, ctx);
       if (cpi->sf.adaptive_pred_interp_filter && bsize == BLOCK_8X8 &&
           partition_none_allowed)
-        get_block_context(x, subsize)->pred_interp_filter =
+        pc_tree->vertical[1].pred_interp_filter =
             ctx->mic.mbmi.interp_filter;
       rd_pick_sb_modes(cpi, tile, mi_row, mi_col + mi_step, &this_rate,
-                       &this_dist, subsize, get_block_context(x, subsize),
-                       best_rd - sum_rd);
+                       &this_dist, subsize,
+                       &pc_tree->vertical[1], best_rd - sum_rd,
+                       1);
       if (this_rate == INT_MAX) {
         sum_rd = INT64_MAX;
       } else {
@@ -2424,12 +2150,11 @@
         best_rate = sum_rate;
         best_dist = sum_dist;
         best_rd = sum_rd;
-        *(get_sb_partitioning(x, bsize)) = subsize;
+        pc_tree->partitioning = PARTITION_VERT;
       }
     }
     restore_context(cpi, mi_row, mi_col, a, l, sa, sl, bsize);
   }
-
   // TODO(jbb): This code added so that we avoid static analysis
   // warning related to the fact that best_rd isn't used after this
   // point.  This code should be refactored so that the duplicate
@@ -2444,17 +2169,16 @@
     // Check the projected output rate for this SB against it's target
     // and and if necessary apply a Q delta using segmentation to get
     // closer to the target.
-    if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map) {
+    if ((cpi->oxcf.aq_mode == COMPLEXITY_AQ) && cm->seg.update_map)
       vp9_select_in_frame_q_segment(cpi, mi_row, mi_col, output_enabled,
                                     best_rate);
-    }
-
     if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
       vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
                                               best_rate, best_dist);
 
-    encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize);
+    encode_sb(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize, pc_tree);
   }
+
   if (bsize == BLOCK_64X64) {
     assert(tp_orig < *tp);
     assert(best_rate < INT_MAX);
@@ -2481,18 +2205,18 @@
     int dummy_rate;
     int64_t dummy_dist;
 
-    BLOCK_SIZE i;
+    int i;
     MACROBLOCK *x = &cpi->mb;
 
     if (sf->adaptive_pred_interp_filter) {
-      for (i = BLOCK_4X4; i < BLOCK_8X8; ++i) {
-        const int num_4x4_w = num_4x4_blocks_wide_lookup[i];
-        const int num_4x4_h = num_4x4_blocks_high_lookup[i];
-        const int num_4x4_blk = MAX(4, num_4x4_w * num_4x4_h);
-        for (x->sb_index = 0; x->sb_index < 4; ++x->sb_index)
-          for (x->mb_index = 0; x->mb_index < 4; ++x->mb_index)
-            for (x->b_index = 0; x->b_index < 16 / num_4x4_blk; ++x->b_index)
-              get_block_context(x, i)->pred_interp_filter = SWITCHABLE;
+      for (i = 0; i < 64; ++i)
+        x->leaf_tree[i].pred_interp_filter = SWITCHABLE;
+
+      for (i = 0; i < 64; ++i) {
+        x->pc_tree[i].vertical[0].pred_interp_filter = SWITCHABLE;
+        x->pc_tree[i].vertical[1].pred_interp_filter = SWITCHABLE;
+        x->pc_tree[i].horizontal[0].pred_interp_filter = SWITCHABLE;
+        x->pc_tree[i].horizontal[1].pred_interp_filter = SWITCHABLE;
       }
     }
 
@@ -2512,18 +2236,18 @@
         set_fixed_partitioning(cpi, tile, mi_8x8, mi_row, mi_col,
                                sf->always_this_block_size);
         rd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                         &dummy_rate, &dummy_dist, 1);
+                         &dummy_rate, &dummy_dist, 1, x->pc_root, 0);
       } else if (sf->partition_search_type == VAR_BASED_FIXED_PARTITION) {
         BLOCK_SIZE bsize;
         set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
         bsize = get_rd_var_based_fixed_partition(cpi, mi_row, mi_col);
         set_fixed_partitioning(cpi, tile, mi_8x8, mi_row, mi_col, bsize);
         rd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                         &dummy_rate, &dummy_dist, 1);
+                         &dummy_rate, &dummy_dist, 1, x->pc_root, 0);
       } else if (sf->partition_search_type == VAR_BASED_PARTITION) {
         choose_partitioning(cpi, tile, mi_row, mi_col);
         rd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                         &dummy_rate, &dummy_dist, 1);
+                         &dummy_rate, &dummy_dist, 1, x->pc_root, 0);
       } else {
         if ((cm->current_video_frame
             % sf->last_partitioning_redo_frequency) == 0
@@ -2542,7 +2266,8 @@
                                     &sf->max_partition_size);
           }
           rd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
-                            &dummy_rate, &dummy_dist, 1, INT64_MAX);
+                            &dummy_rate, &dummy_dist, 1, INT64_MAX, x->pc_root,
+                            0);
         } else {
           if (sf->constrain_copy_partition &&
               sb_has_motion(cm, prev_mi_8x8))
@@ -2551,7 +2276,7 @@
           else
             copy_partitioning(cm, mi_8x8, prev_mi_8x8);
           rd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                           &dummy_rate, &dummy_dist, 1);
+                           &dummy_rate, &dummy_dist, 1, x->pc_root, 0);
         }
       }
     } else {
@@ -2563,7 +2288,7 @@
                                 &sf->max_partition_size);
       }
       rd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
-                        &dummy_rate, &dummy_dist, 1, INT64_MAX);
+                        &dummy_rate, &dummy_dist, 1, INT64_MAX, x->pc_root, 0);
     }
   }
 }
@@ -2574,21 +2299,11 @@
   MACROBLOCKD *const xd = &x->e_mbd;
   const int aligned_mi_cols = mi_cols_aligned_to_sb(cm->mi_cols);
 
-  x->act_zbin_adj = 0;
-
   // Copy data over into macro block data structures.
   vp9_setup_src_planes(x, cpi->Source, 0, 0);
 
-  // TODO(jkoleszar): are these initializations required?
-  vp9_setup_pre_planes(xd, 0, get_ref_frame_buffer(cpi, LAST_FRAME), 0, 0,
-                       NULL);
-  vp9_setup_dst_planes(xd, get_frame_new_buffer(cm), 0, 0);
-
   vp9_setup_block_planes(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
 
-  xd->mi[0]->mbmi.mode = DC_PRED;
-  xd->mi[0]->mbmi.uv_mode = DC_PRED;
-
   // Note: this memset assumes above_context[0], [1] and [2]
   // are allocated as part of the same buffer.
   vpx_memset(xd->above_context[0], 0,
@@ -2658,9 +2373,10 @@
     if (cpi->sf.tx_size_search_method == USE_LARGESTALL) {
       return ALLOW_32X32;
     } else if (cpi->sf.tx_size_search_method == USE_FULL_RD) {
+      const RD_OPT *const rd_opt = &cpi->rd;
       const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi);
-      return cpi->rd_tx_select_threshes[frame_type][ALLOW_32X32] >
-                 cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] ?
+      return rd_opt->tx_select_threshes[frame_type][ALLOW_32X32] >
+                 rd_opt->tx_select_threshes[frame_type][TX_MODE_SELECT] ?
                      ALLOW_32X32 : TX_MODE_SELECT;
     } else {
       unsigned int total = 0;
@@ -2691,7 +2407,7 @@
 } motion_vector_context;
 
 static void set_mode_info(MB_MODE_INFO *mbmi, BLOCK_SIZE bsize,
-                          MB_PREDICTION_MODE mode) {
+                          PREDICTION_MODE mode) {
   mbmi->mode = mode;
   mbmi->uv_mode = mode;
   mbmi->mv[0].as_int = 0;
@@ -2714,22 +2430,27 @@
   set_offsets(cpi, tile, mi_row, mi_col, bsize);
   xd->mi[0]->mbmi.sb_type = bsize;
 
+  if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled) {
+    if (xd->mi[0]->mbmi.segment_id && x->in_static_area)
+      x->rdmult = vp9_cyclic_refresh_get_rdmult(cpi->cyclic_refresh);
+  }
+
   if (!frame_is_intra_only(cm)) {
     vp9_pick_inter_mode(cpi, x, tile, mi_row, mi_col,
                         rate, dist, bsize);
   } else {
-    MB_PREDICTION_MODE intramode = DC_PRED;
-    set_mode_info(&xd->mi[0]->mbmi, bsize, intramode);
+    set_mode_info(&xd->mi[0]->mbmi, bsize, DC_PRED);
   }
   duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
 }
 
 static void fill_mode_info_sb(VP9_COMMON *cm, MACROBLOCK *x,
                               int mi_row, int mi_col,
-                              BLOCK_SIZE bsize, BLOCK_SIZE subsize) {
+                              BLOCK_SIZE bsize, BLOCK_SIZE subsize,
+                              PC_TREE *pc_tree) {
   MACROBLOCKD *xd = &x->e_mbd;
   int bsl = b_width_log2(bsize), hbs = (1 << bsl) / 4;
-  PARTITION_TYPE partition = partition_lookup[bsl][subsize];
+  PARTITION_TYPE partition = pc_tree->partitioning;
 
   assert(bsize >= BLOCK_8X8);
 
@@ -2739,48 +2460,42 @@
   switch (partition) {
     case PARTITION_NONE:
       set_modeinfo_offsets(cm, xd, mi_row, mi_col);
-      *(xd->mi[0]) = get_block_context(x, subsize)->mic;
+      *(xd->mi[0]) = pc_tree->none.mic;
       duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
       break;
     case PARTITION_VERT:
-      *get_sb_index(x, subsize) = 0;
       set_modeinfo_offsets(cm, xd, mi_row, mi_col);
-      *(xd->mi[0]) = get_block_context(x, subsize)->mic;
+      *(xd->mi[0]) = pc_tree->vertical[0].mic;
       duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
 
       if (mi_col + hbs < cm->mi_cols) {
-        *get_sb_index(x, subsize) = 1;
         set_modeinfo_offsets(cm, xd, mi_row, mi_col + hbs);
-        *(xd->mi[0]) = get_block_context(x, subsize)->mic;
+        *(xd->mi[0]) = pc_tree->vertical[1].mic;
         duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col + hbs, bsize);
       }
       break;
     case PARTITION_HORZ:
-      *get_sb_index(x, subsize) = 0;
       set_modeinfo_offsets(cm, xd, mi_row, mi_col);
-      *(xd->mi[0]) = get_block_context(x, subsize)->mic;
+      *(xd->mi[0]) = pc_tree->horizontal[0].mic;
       duplicate_mode_info_in_sb(cm, xd, mi_row, mi_col, bsize);
       if (mi_row + hbs < cm->mi_rows) {
-        *get_sb_index(x, subsize) = 1;
         set_modeinfo_offsets(cm, xd, mi_row + hbs, mi_col);
-        *(xd->mi[0]) = get_block_context(x, subsize)->mic;
+        *(xd->mi[0]) = pc_tree->horizontal[1].mic;
         duplicate_mode_info_in_sb(cm, xd, mi_row + hbs, mi_col, bsize);
       }
       break;
-    case PARTITION_SPLIT:
-      *get_sb_index(x, subsize) = 0;
+    case PARTITION_SPLIT: {
+      BLOCK_SIZE subsubsize = get_subsize(subsize, PARTITION_SPLIT);
       fill_mode_info_sb(cm, x, mi_row, mi_col, subsize,
-                        *(get_sb_partitioning(x, subsize)));
-      *get_sb_index(x, subsize) = 1;
+                        subsubsize, pc_tree->split[0]);
       fill_mode_info_sb(cm, x, mi_row, mi_col + hbs, subsize,
-                        *(get_sb_partitioning(x, subsize)));
-      *get_sb_index(x, subsize) = 2;
+                        subsubsize, pc_tree->split[1]);
       fill_mode_info_sb(cm, x, mi_row + hbs, mi_col, subsize,
-                        *(get_sb_partitioning(x, subsize)));
-      *get_sb_index(x, subsize) = 3;
+                        subsubsize, pc_tree->split[2]);
       fill_mode_info_sb(cm, x, mi_row + hbs, mi_col + hbs, subsize,
-                        *(get_sb_partitioning(x, subsize)));
+                        subsubsize, pc_tree->split[3]);
       break;
+    }
     default:
       break;
   }
@@ -2789,15 +2504,16 @@
 static void nonrd_pick_partition(VP9_COMP *cpi, const TileInfo *const tile,
                                  TOKENEXTRA **tp, int mi_row,
                                  int mi_col, BLOCK_SIZE bsize, int *rate,
-                                 int64_t *dist, int do_recon, int64_t best_rd) {
+                                 int64_t *dist, int do_recon, int64_t best_rd,
+                                 PC_TREE *pc_tree) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
   const int ms = num_8x8_blocks_wide_lookup[bsize] / 2;
   TOKENEXTRA *tp_orig = *tp;
-  PICK_MODE_CONTEXT *ctx = get_block_context(x, bsize);
+  PICK_MODE_CONTEXT *ctx = &pc_tree->none;
   int i;
-  BLOCK_SIZE subsize;
+  BLOCK_SIZE subsize = bsize;
   int this_rate, sum_rate = 0, best_rate = INT_MAX;
   int64_t this_dist, sum_dist = 0, best_dist = INT64_MAX;
   int64_t sum_rd = 0;
@@ -2816,16 +2532,6 @@
                                bsize >= BLOCK_8X8;
   (void) *tp_orig;
 
-  if (bsize < BLOCK_8X8) {
-    // When ab_index = 0 all sub-blocks are handled, so for ab_index != 0
-    // there is nothing to be done.
-    if (x->ab_index != 0) {
-      *rate = 0;
-      *dist = 0;
-      return;
-    }
-  }
-
   assert(num_8x8_blocks_wide_lookup[bsize] ==
              num_8x8_blocks_high_lookup[bsize]);
 
@@ -2870,7 +2576,7 @@
         best_dist = this_dist;
         best_rd = sum_rd;
         if (bsize >= BLOCK_8X8)
-          *(get_sb_partitioning(x, bsize)) = bsize;
+          pc_tree->partitioning = PARTITION_NONE;
 
         // Adjust threshold according to partition size.
         stop_thresh >>= 8 - (b_width_log2_lookup[bsize] +
@@ -2907,12 +2613,11 @@
       if (mi_row + y_idx >= cm->mi_rows || mi_col + x_idx >= cm->mi_cols)
         continue;
 
-      *get_sb_index(x, subsize) = i;
       load_pred_mv(x, ctx);
 
       nonrd_pick_partition(cpi, tile, tp, mi_row + y_idx, mi_col + x_idx,
                            subsize, &this_rate, &this_dist, 0,
-                           best_rd - sum_rd);
+                           best_rd - sum_rd, pc_tree->split[i]);
 
       if (this_rate == INT_MAX) {
         sum_rd = INT64_MAX;
@@ -2927,7 +2632,7 @@
       best_rate = sum_rate;
       best_dist = sum_dist;
       best_rd = sum_rd;
-      *(get_sb_partitioning(x, bsize)) = subsize;
+      pc_tree->partitioning = PARTITION_SPLIT;
     } else {
       // skip rectangular partition test when larger block size
       // gives better rd cost
@@ -2939,26 +2644,22 @@
   // PARTITION_HORZ
   if (partition_horz_allowed && do_rect) {
     subsize = get_subsize(bsize, PARTITION_HORZ);
-    *get_sb_index(x, subsize) = 0;
     if (cpi->sf.adaptive_motion_search)
       load_pred_mv(x, ctx);
 
     nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col,
                         &this_rate, &this_dist, subsize);
 
-    get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+    pc_tree->horizontal[0].mic.mbmi = xd->mi[0]->mbmi;
 
     sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
 
     if (sum_rd < best_rd && mi_row + ms < cm->mi_rows) {
-      *get_sb_index(x, subsize) = 1;
-
       load_pred_mv(x, ctx);
-
       nonrd_pick_sb_modes(cpi, tile, mi_row + ms, mi_col,
                           &this_rate, &this_dist, subsize);
 
-      get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+      pc_tree->horizontal[1].mic.mbmi = xd->mi[0]->mbmi;
 
       if (this_rate == INT_MAX) {
         sum_rd = INT64_MAX;
@@ -2974,7 +2675,7 @@
       best_rd = sum_rd;
       best_rate = sum_rate;
       best_dist = sum_dist;
-      *(get_sb_partitioning(x, bsize)) = subsize;
+      pc_tree->partitioning = PARTITION_HORZ;
     }
   }
 
@@ -2982,24 +2683,18 @@
   if (partition_vert_allowed && do_rect) {
     subsize = get_subsize(bsize, PARTITION_VERT);
 
-    *get_sb_index(x, subsize) = 0;
     if (cpi->sf.adaptive_motion_search)
       load_pred_mv(x, ctx);
 
     nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col,
                         &this_rate, &this_dist, subsize);
-    get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+    pc_tree->vertical[0].mic.mbmi = xd->mi[0]->mbmi;
     sum_rd = RDCOST(x->rdmult, x->rddiv, sum_rate, sum_dist);
     if (sum_rd < best_rd && mi_col + ms < cm->mi_cols) {
-      *get_sb_index(x, subsize) = 1;
-
       load_pred_mv(x, ctx);
-
       nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col + ms,
                           &this_rate, &this_dist, subsize);
-
-      get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
-
+      pc_tree->vertical[1].mic.mbmi = xd->mi[0]->mbmi;
       if (this_rate == INT_MAX) {
         sum_rd = INT64_MAX;
       } else {
@@ -3014,9 +2709,13 @@
       best_rate = sum_rate;
       best_dist = sum_dist;
       best_rd = sum_rd;
-      *(get_sb_partitioning(x, bsize)) = subsize;
+      pc_tree->partitioning = PARTITION_VERT;
     }
   }
+  // TODO(JBB): The following line is here just to avoid a static warning
+  // that occurs because at this point we never again reuse best_rd
+  // despite setting it here.  The code should be refactored to avoid this.
+  (void) best_rd;
 
   *rate = best_rate;
   *dist = best_dist;
@@ -3025,8 +2724,9 @@
     return;
 
   // update mode info array
-  fill_mode_info_sb(cm, x, mi_row, mi_col, bsize,
-                    *(get_sb_partitioning(x, bsize)));
+  subsize = get_subsize(bsize, pc_tree->partitioning);
+  fill_mode_info_sb(cm, x, mi_row, mi_col, bsize, subsize,
+                    pc_tree);
 
   if (best_rate < INT_MAX && best_dist < INT64_MAX && do_recon) {
     int output_enabled = (bsize == BLOCK_64X64);
@@ -3043,7 +2743,7 @@
       vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
                                               best_rate, best_dist);
 
-    encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize);
+    encode_sb_rt(cpi, tile, tp, mi_row, mi_col, output_enabled, bsize, pc_tree);
   }
 
   if (bsize == BLOCK_64X64) {
@@ -3061,7 +2761,8 @@
                                 TOKENEXTRA **tp,
                                 int mi_row, int mi_col,
                                 BLOCK_SIZE bsize, int output_enabled,
-                                int *totrate, int64_t *totdist) {
+                                int *totrate, int64_t *totdist,
+                                PC_TREE *pc_tree) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -3081,17 +2782,15 @@
   switch (partition) {
     case PARTITION_NONE:
       nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, totrate, totdist, subsize);
-      get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+      pc_tree->none.mic.mbmi = xd->mi[0]->mbmi;
       break;
     case PARTITION_VERT:
-      *get_sb_index(x, subsize) = 0;
       nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, totrate, totdist, subsize);
-      get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+      pc_tree->vertical[0].mic.mbmi = xd->mi[0]->mbmi;
       if (mi_col + hbs < cm->mi_cols) {
-        *get_sb_index(x, subsize) = 1;
         nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col + hbs,
                             &rate, &dist, subsize);
-        get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+        pc_tree->vertical[1].mic.mbmi = xd->mi[0]->mbmi;
         if (rate != INT_MAX && dist != INT64_MAX &&
             *totrate != INT_MAX && *totdist != INT64_MAX) {
           *totrate += rate;
@@ -3100,14 +2799,12 @@
       }
       break;
     case PARTITION_HORZ:
-      *get_sb_index(x, subsize) = 0;
       nonrd_pick_sb_modes(cpi, tile, mi_row, mi_col, totrate, totdist, subsize);
-      get_block_context(x, subsize)->mic.mbmi = xd->mi[0]->mbmi;
+      pc_tree->horizontal[0].mic.mbmi = xd->mi[0]->mbmi;
       if (mi_row + hbs < cm->mi_rows) {
-        *get_sb_index(x, subsize) = 1;
         nonrd_pick_sb_modes(cpi, tile, mi_row + hbs, mi_col,
                             &rate, &dist, subsize);
-        get_block_context(x, subsize)->mic.mbmi = mi_8x8[0]->mbmi;
+        pc_tree->horizontal[1].mic.mbmi = mi_8x8[0]->mbmi;
         if (rate != INT_MAX && dist != INT64_MAX &&
             *totrate != INT_MAX && *totdist != INT64_MAX) {
           *totrate += rate;
@@ -3117,31 +2814,28 @@
       break;
     case PARTITION_SPLIT:
       subsize = get_subsize(bsize, PARTITION_SPLIT);
-      *get_sb_index(x, subsize) = 0;
       nonrd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col,
-                          subsize, output_enabled, totrate, totdist);
-      *get_sb_index(x, subsize) = 1;
+                          subsize, output_enabled, totrate, totdist,
+                          pc_tree->split[0]);
       nonrd_use_partition(cpi, tile, mi_8x8 + hbs, tp,
                           mi_row, mi_col + hbs, subsize, output_enabled,
-                          &rate, &dist);
+                          &rate, &dist, pc_tree->split[1]);
       if (rate != INT_MAX && dist != INT64_MAX &&
           *totrate != INT_MAX && *totdist != INT64_MAX) {
         *totrate += rate;
         *totdist += dist;
       }
-      *get_sb_index(x, subsize) = 2;
       nonrd_use_partition(cpi, tile, mi_8x8 + hbs * mis, tp,
                           mi_row + hbs, mi_col, subsize, output_enabled,
-                          &rate, &dist);
+                          &rate, &dist, pc_tree->split[2]);
       if (rate != INT_MAX && dist != INT64_MAX &&
           *totrate != INT_MAX && *totdist != INT64_MAX) {
         *totrate += rate;
         *totdist += dist;
       }
-      *get_sb_index(x, subsize) = 3;
       nonrd_use_partition(cpi, tile, mi_8x8 + hbs * mis + hbs, tp,
                           mi_row + hbs, mi_col + hbs, subsize, output_enabled,
-                          &rate, &dist);
+                          &rate, &dist, pc_tree->split[3]);
       if (rate != INT_MAX && dist != INT64_MAX &&
           *totrate != INT_MAX && *totdist != INT64_MAX) {
         *totrate += rate;
@@ -3156,14 +2850,15 @@
     if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
       vp9_cyclic_refresh_set_rate_and_dist_sb(cpi->cyclic_refresh,
                                               *totrate, *totdist);
-    encode_sb_rt(cpi, tile, tp, mi_row, mi_col, 1, bsize);
+    encode_sb_rt(cpi, tile, tp, mi_row, mi_col, 1, bsize, pc_tree);
   }
 }
 
 static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile,
                                 int mi_row, TOKENEXTRA **tp) {
   VP9_COMMON *cm = &cpi->common;
-  MACROBLOCKD *xd = &cpi->mb.e_mbd;
+  MACROBLOCK *x = &cpi->mb;
+  MACROBLOCKD *xd = &x->e_mbd;
   int mi_col;
 
   // Initialize the left context for the new SB row
@@ -3173,6 +2868,7 @@
   // Code each SB in the row
   for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end;
        mi_col += MI_BLOCK_SIZE) {
+    MACROBLOCK *x = &cpi->mb;
     int dummy_rate = 0;
     int64_t dummy_dist = 0;
     const int idx_str = cm->mi_stride * mi_row + mi_col;
@@ -3180,21 +2876,21 @@
     MODE_INFO **prev_mi_8x8 = cm->prev_mi_grid_visible + idx_str;
     BLOCK_SIZE bsize;
 
-    cpi->mb.source_variance = UINT_MAX;
-    vp9_zero(cpi->mb.pred_mv);
+    x->in_static_area = 0;
+    x->source_variance = UINT_MAX;
+    vp9_zero(x->pred_mv);
 
     // Set the partition type of the 64X64 block
     switch (cpi->sf.partition_search_type) {
       case VAR_BASED_PARTITION:
         choose_partitioning(cpi, tile, mi_row, mi_col);
         nonrd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                            1, &dummy_rate, &dummy_dist);
+                            1, &dummy_rate, &dummy_dist, x->pc_root);
         break;
       case SOURCE_VAR_BASED_PARTITION:
-        set_offsets(cpi, tile, mi_row, mi_col, BLOCK_64X64);
         set_source_var_based_partition(cpi, tile, mi_8x8, mi_row, mi_col);
         nonrd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                            1, &dummy_rate, &dummy_dist);
+                            1, &dummy_rate, &dummy_dist, x->pc_root);
         break;
       case VAR_BASED_FIXED_PARTITION:
       case FIXED_PARTITION:
@@ -3203,16 +2899,19 @@
                 get_nonrd_var_based_fixed_partition(cpi, mi_row, mi_col);
         set_fixed_partitioning(cpi, tile, mi_8x8, mi_row, mi_col, bsize);
         nonrd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col, BLOCK_64X64,
-                            1, &dummy_rate, &dummy_dist);
+                            1, &dummy_rate, &dummy_dist, x->pc_root);
         break;
       case REFERENCE_PARTITION:
-        if (cpi->sf.partition_check || sb_has_motion(cm, prev_mi_8x8)) {
+        if (cpi->sf.partition_check ||
+            !is_background(cpi, tile, mi_row, mi_col)) {
           nonrd_pick_partition(cpi, tile, tp, mi_row, mi_col, BLOCK_64X64,
-                               &dummy_rate, &dummy_dist, 1, INT64_MAX);
+                               &dummy_rate, &dummy_dist, 1, INT64_MAX,
+                               x->pc_root);
         } else {
           copy_partitioning(cm, mi_8x8, prev_mi_8x8);
           nonrd_use_partition(cpi, tile, mi_8x8, tp, mi_row, mi_col,
-                              BLOCK_64X64, 1, &dummy_rate, &dummy_dist);
+                              BLOCK_64X64, 1, &dummy_rate, &dummy_dist,
+                              x->pc_root);
         }
         break;
       default:
@@ -3222,8 +2921,23 @@
 }
 // end RTC play code
 
+static int get_skip_encode_frame(const VP9_COMMON *cm) {
+  unsigned int intra_count = 0, inter_count = 0;
+  int j;
+
+  for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) {
+    intra_count += cm->counts.intra_inter[j][0];
+    inter_count += cm->counts.intra_inter[j][1];
+  }
+
+  return (intra_count << 2) < inter_count &&
+         cm->frame_type != KEY_FRAME &&
+         cm->show_frame;
+}
+
 static void encode_frame_internal(VP9_COMP *cpi) {
   SPEED_FEATURES *const sf = &cpi->sf;
+  RD_OPT *const rd_opt = &cpi->rd;
   MACROBLOCK *const x = &cpi->mb;
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -3234,10 +2948,10 @@
   vp9_zero(cm->counts);
   vp9_zero(cpi->coef_counts);
   vp9_zero(cpi->tx_stepdown_count);
-  vp9_zero(cpi->rd_comp_pred_diff);
-  vp9_zero(cpi->rd_filter_diff);
-  vp9_zero(cpi->rd_tx_select_diff);
-  vp9_zero(cpi->rd_tx_select_threshes);
+  vp9_zero(rd_opt->comp_pred_diff);
+  vp9_zero(rd_opt->filter_diff);
+  vp9_zero(rd_opt->tx_select_diff);
+  vp9_zero(rd_opt->tx_select_threshes);
 
   cm->tx_mode = select_tx_mode(cpi);
 
@@ -3252,10 +2966,6 @@
   vp9_initialize_rd_consts(cpi);
   vp9_initialize_me_consts(cpi, cm->base_qindex);
   init_encode_frame_mb_context(cpi);
-
-  if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
-    build_activity_map(cpi);
-
   set_prev_mi(cm);
 
   if (sf->use_nonrd_pick_mode) {
@@ -3264,7 +2974,7 @@
     int i;
     struct macroblock_plane *const p = x->plane;
     struct macroblockd_plane *const pd = xd->plane;
-    PICK_MODE_CONTEXT *ctx = &cpi->mb.sb64_context;
+    PICK_MODE_CONTEXT *ctx = &x->pc_root->none;
 
     for (i = 0; i < MAX_MB_PLANE; ++i) {
       p[i].coeff = ctx->coeff_pbuf[i][0];
@@ -3334,19 +3044,7 @@
     cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer);
   }
 
-  if (sf->skip_encode_sb) {
-    int j;
-    unsigned int intra_count = 0, inter_count = 0;
-    for (j = 0; j < INTRA_INTER_CONTEXTS; ++j) {
-      intra_count += cm->counts.intra_inter[j][0];
-      inter_count += cm->counts.intra_inter[j][1];
-    }
-    sf->skip_encode_frame = (intra_count << 2) < inter_count &&
-                            cm->frame_type != KEY_FRAME &&
-                            cm->show_frame;
-  } else {
-    sf->skip_encode_frame = 0;
-  }
+  sf->skip_encode_frame = sf->skip_encode_sb ? get_skip_encode_frame(cm) : 0;
 
 #if 0
   // Keep record of the total distortion this time around for future use
@@ -3356,6 +3054,7 @@
 
 void vp9_encode_frame(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
+  RD_OPT *const rd_opt = &cpi->rd;
 
   // In the longer term the encoder should be generalized to match the
   // decoder such that we allow compound where one of the 3 buffers has a
@@ -3388,8 +3087,8 @@
     // that for subsequent frames.
     // It does the same analysis for transform size selection also.
     const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi);
-    const int64_t *mode_thresh = cpi->rd_prediction_type_threshes[frame_type];
-    const int64_t *filter_thresh = cpi->rd_filter_threshes[frame_type];
+    const int64_t *mode_thresh = rd_opt->prediction_type_threshes[frame_type];
+    const int64_t *filter_thresh = rd_opt->filter_threshes[frame_type];
 
     /* prediction (compound, single or hybrid) mode selection */
     if (frame_type == ALTREF_FRAME || !cm->allow_comp_inter_inter)
@@ -3422,25 +3121,25 @@
     encode_frame_internal(cpi);
 
     for (i = 0; i < REFERENCE_MODES; ++i) {
-      const int diff = (int) (cpi->rd_comp_pred_diff[i] / cm->MBs);
-      cpi->rd_prediction_type_threshes[frame_type][i] += diff;
-      cpi->rd_prediction_type_threshes[frame_type][i] >>= 1;
+      const int diff = (int) (rd_opt->comp_pred_diff[i] / cm->MBs);
+      rd_opt->prediction_type_threshes[frame_type][i] += diff;
+      rd_opt->prediction_type_threshes[frame_type][i] >>= 1;
     }
 
     for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
-      const int64_t diff = cpi->rd_filter_diff[i] / cm->MBs;
-      cpi->rd_filter_threshes[frame_type][i] =
-          (cpi->rd_filter_threshes[frame_type][i] + diff) / 2;
+      const int64_t diff = rd_opt->filter_diff[i] / cm->MBs;
+      rd_opt->filter_threshes[frame_type][i] =
+          (rd_opt->filter_threshes[frame_type][i] + diff) / 2;
     }
 
     for (i = 0; i < TX_MODES; ++i) {
-      int64_t pd = cpi->rd_tx_select_diff[i];
+      int64_t pd = rd_opt->tx_select_diff[i];
       int diff;
       if (i == TX_MODE_SELECT)
         pd -= RDCOST(cpi->mb.rdmult, cpi->mb.rddiv, 2048 * (TX_SIZES - 1), 0);
       diff = (int) (pd / cm->MBs);
-      cpi->rd_tx_select_threshes[frame_type][i] += diff;
-      cpi->rd_tx_select_threshes[frame_type][i] /= 2;
+      rd_opt->tx_select_threshes[frame_type][i] += diff;
+      rd_opt->tx_select_threshes[frame_type][i] /= 2;
     }
 
     if (cm->reference_mode == REFERENCE_MODE_SELECT) {
@@ -3504,8 +3203,8 @@
 }
 
 static void sum_intra_stats(FRAME_COUNTS *counts, const MODE_INFO *mi) {
-  const MB_PREDICTION_MODE y_mode = mi->mbmi.mode;
-  const MB_PREDICTION_MODE uv_mode = mi->mbmi.uv_mode;
+  const PREDICTION_MODE y_mode = mi->mbmi.mode;
+  const PREDICTION_MODE uv_mode = mi->mbmi.uv_mode;
   const BLOCK_SIZE bsize = mi->mbmi.sb_type;
 
   if (bsize < BLOCK_8X8) {
@@ -3522,24 +3221,6 @@
   ++counts->uv_mode[y_mode][uv_mode];
 }
 
-// Experimental stub function to create a per MB zbin adjustment based on
-// some previously calculated measure of MB activity.
-static void adjust_act_zbin(VP9_COMP *cpi, MACROBLOCK *x) {
-#if USE_ACT_INDEX
-  x->act_zbin_adj = *(x->mb_activity_ptr);
-#else
-  // Apply the masking to the RD multiplier.
-  const int64_t act = *(x->mb_activity_ptr);
-  const int64_t a = act + 4 * cpi->activity_avg;
-  const int64_t b = 4 * act + cpi->activity_avg;
-
-  if (act > cpi->activity_avg)
-    x->act_zbin_adj = (int) (((int64_t) b + (a >> 1)) / a) - 1;
-  else
-    x->act_zbin_adj = 1 - (int) (((int64_t) a + (b >> 1)) / b);
-#endif
-}
-
 static int get_zbin_mode_boost(const MB_MODE_INFO *mbmi, int enabled) {
   if (enabled) {
     if (is_inter_block(mbmi)) {
@@ -3559,14 +3240,14 @@
 }
 
 static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
-                              int mi_row, int mi_col, BLOCK_SIZE bsize) {
+                              int mi_row, int mi_col, BLOCK_SIZE bsize,
+                              PICK_MODE_CONTEXT *ctx) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
   MODE_INFO **mi_8x8 = xd->mi;
   MODE_INFO *mi = mi_8x8[0];
   MB_MODE_INFO *mbmi = &mi->mbmi;
-  PICK_MODE_CONTEXT *ctx = get_block_context(x, bsize);
   unsigned int segment_id = mbmi->segment_id;
   const int mis = cm->mi_stride;
   const int mi_width = num_8x8_blocks_wide_lookup[bsize];
@@ -3586,25 +3267,13 @@
   if (x->skip_encode)
     return;
 
-  if (cm->frame_type == KEY_FRAME) {
-    if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
-      adjust_act_zbin(cpi, x);
-      vp9_update_zbin_extra(cpi, x);
-    }
-  } else {
-    set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
+  set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
 
-    if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
-      // Adjust the zbin based on this MB rate.
-      adjust_act_zbin(cpi, x);
-    }
-
-    // Experimental code. Special case for gf and arf zeromv modes.
-    // Increase zbin size to suppress noise
-    cpi->zbin_mode_boost = get_zbin_mode_boost(mbmi,
-                                               cpi->zbin_mode_boost_enabled);
-    vp9_update_zbin_extra(cpi, x);
-  }
+  // Experimental code. Special case for gf and arf zeromv modes.
+  // Increase zbin size to suppress noise
+  cpi->zbin_mode_boost = get_zbin_mode_boost(mbmi,
+                                             cpi->zbin_mode_boost_enabled);
+  vp9_update_zbin_extra(cpi, x);
 
   if (!is_inter_block(mbmi)) {
     int plane;
diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c
index 5e98e4e..d71b16f 100644
--- a/vp9/encoder/vp9_encodemb.c
+++ b/vp9/encoder/vp9_encodemb.c
@@ -63,24 +63,17 @@
 }
 
 #define RDTRUNC(RM, DM, R, D) ((128 + (R) * (RM)) & 0xFF)
-typedef struct vp9_token_state vp9_token_state;
 
-struct vp9_token_state {
+typedef struct vp9_token_state {
   int           rate;
   int           error;
   int           next;
   signed char   token;
   short         qc;
-};
+} vp9_token_state;
 
 // TODO(jimbankoski): experiment to find optimal RD numbers.
-#define Y1_RD_MULT 4
-#define UV_RD_MULT 2
-
-static const int plane_rd_mult[4] = {
-  Y1_RD_MULT,
-  UV_RD_MULT,
-};
+static const int plane_rd_mult[PLANE_TYPES] = { 4, 2 };
 
 #define UPDATE_RD_COST()\
 {\
@@ -105,60 +98,56 @@
   return pt;
 }
 
-static void optimize_b(int plane, int block, BLOCK_SIZE plane_bsize,
-                       TX_SIZE tx_size, MACROBLOCK *mb,
-                       ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l) {
+static int optimize_b(MACROBLOCK *mb, int plane, int block,
+                      BLOCK_SIZE plane_bsize, TX_SIZE tx_size, int ctx) {
   MACROBLOCKD *const xd = &mb->e_mbd;
-  struct macroblock_plane *p = &mb->plane[plane];
-  struct macroblockd_plane *pd = &xd->plane[plane];
+  struct macroblock_plane *const p = &mb->plane[plane];
+  struct macroblockd_plane *const pd = &xd->plane[plane];
   const int ref = is_inter_block(&xd->mi[0]->mbmi);
   vp9_token_state tokens[1025][2];
   unsigned best_index[1025][2];
-  const int16_t *coeff = BLOCK_OFFSET(mb->plane[plane].coeff, block);
-  int16_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
-  int16_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
-  int eob = p->eobs[block], final_eob, sz = 0;
-  const int i0 = 0;
-  int rc, x, next, i;
-  int64_t rdmult, rddiv, rd_cost0, rd_cost1;
-  int rate0, rate1, error0, error1, t0, t1;
-  int best, band, pt;
-  PLANE_TYPE type = pd->plane_type;
-  int err_mult = plane_rd_mult[type];
+  uint8_t token_cache[1024];
+  const int16_t *const coeff = BLOCK_OFFSET(mb->plane[plane].coeff, block);
+  int16_t *const qcoeff = BLOCK_OFFSET(p->qcoeff, block);
+  int16_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
+  const int eob = p->eobs[block];
+  const PLANE_TYPE type = pd->plane_type;
   const int default_eob = 16 << (tx_size << 1);
   const int mul = 1 + (tx_size == TX_32X32);
-  uint8_t token_cache[1024];
   const int16_t *dequant_ptr = pd->dequant;
   const uint8_t *const band_translate = get_band_translate(tx_size);
-  const scan_order *so = get_scan(xd, tx_size, type, block);
-  const int16_t *scan = so->scan;
-  const int16_t *nb = so->neighbors;
+  const scan_order *const so = get_scan(xd, tx_size, type, block);
+  const int16_t *const scan = so->scan;
+  const int16_t *const nb = so->neighbors;
+  int next = eob, sz = 0;
+  int64_t rdmult = mb->rdmult * plane_rd_mult[type], rddiv = mb->rddiv;
+  int64_t rd_cost0, rd_cost1;
+  int rate0, rate1, error0, error1, t0, t1;
+  int best, band, pt, i, final_eob;
 
   assert((!type && !plane) || (type && plane));
   assert(eob <= default_eob);
 
   /* Now set up a Viterbi trellis to evaluate alternative roundings. */
-  rdmult = mb->rdmult * err_mult;
-  if (!is_inter_block(&mb->e_mbd.mi[0]->mbmi))
+  if (!ref)
     rdmult = (rdmult * 9) >> 4;
-  rddiv = mb->rddiv;
+
   /* Initialize the sentinel node of the trellis. */
   tokens[eob][0].rate = 0;
   tokens[eob][0].error = 0;
   tokens[eob][0].next = default_eob;
   tokens[eob][0].token = EOB_TOKEN;
   tokens[eob][0].qc = 0;
-  *(tokens[eob] + 1) = *(tokens[eob] + 0);
-  next = eob;
+  tokens[eob][1] = tokens[eob][0];
+
   for (i = 0; i < eob; i++)
-    token_cache[scan[i]] = vp9_pt_energy_class[vp9_dct_value_tokens_ptr[
-        qcoeff[scan[i]]].token];
+    token_cache[scan[i]] =
+        vp9_pt_energy_class[vp9_dct_value_tokens_ptr[qcoeff[scan[i]]].token];
 
-  for (i = eob; i-- > i0;) {
+  for (i = eob; i-- > 0;) {
     int base_bits, d2, dx;
-
-    rc = scan[i];
-    x = qcoeff[rc];
+    const int rc = scan[i];
+    int x = qcoeff[rc];
     /* Only add a trellis state for non-zero coefficients. */
     if (x) {
       int shortcut = 0;
@@ -172,17 +161,15 @@
       if (next < default_eob) {
         band = band_translate[i + 1];
         pt = trellis_get_coeff_context(scan, nb, i, t0, token_cache);
-        rate0 +=
-          mb->token_costs[tx_size][type][ref][band][0][pt]
-                         [tokens[next][0].token];
-        rate1 +=
-          mb->token_costs[tx_size][type][ref][band][0][pt]
-                         [tokens[next][1].token];
+        rate0 += mb->token_costs[tx_size][type][ref][band][0][pt]
+                                [tokens[next][0].token];
+        rate1 += mb->token_costs[tx_size][type][ref][band][0][pt]
+                                [tokens[next][1].token];
       }
       UPDATE_RD_COST();
       /* And pick the best. */
       best = rd_cost1 < rd_cost0;
-      base_bits = *(vp9_dct_value_cost_ptr + x);
+      base_bits = vp9_dct_value_cost_ptr[x];
       dx = mul * (dqcoeff[rc] - coeff[rc]);
       d2 = dx * dx;
       tokens[i][0].rate = base_bits + (best ? rate1 : rate0);
@@ -196,9 +183,9 @@
       rate0 = tokens[next][0].rate;
       rate1 = tokens[next][1].rate;
 
-      if ((abs(x)*dequant_ptr[rc != 0] > abs(coeff[rc]) * mul) &&
-          (abs(x)*dequant_ptr[rc != 0] < abs(coeff[rc]) * mul +
-                                         dequant_ptr[rc != 0]))
+      if ((abs(x) * dequant_ptr[rc != 0] > abs(coeff[rc]) * mul) &&
+          (abs(x) * dequant_ptr[rc != 0] < abs(coeff[rc]) * mul +
+                                               dequant_ptr[rc != 0]))
         shortcut = 1;
       else
         shortcut = 0;
@@ -235,7 +222,7 @@
       UPDATE_RD_COST();
       /* And pick the best. */
       best = rd_cost1 < rd_cost0;
-      base_bits = *(vp9_dct_value_cost_ptr + x);
+      base_bits = vp9_dct_value_cost_ptr[x];
 
       if (shortcut) {
         dx -= (dequant_ptr[rc != 0] + sz) ^ sz;
@@ -274,26 +261,26 @@
 
   /* Now pick the best path through the whole trellis. */
   band = band_translate[i + 1];
-  pt = combine_entropy_contexts(*a, *l);
   rate0 = tokens[next][0].rate;
   rate1 = tokens[next][1].rate;
   error0 = tokens[next][0].error;
   error1 = tokens[next][1].error;
   t0 = tokens[next][0].token;
   t1 = tokens[next][1].token;
-  rate0 += mb->token_costs[tx_size][type][ref][band][0][pt][t0];
-  rate1 += mb->token_costs[tx_size][type][ref][band][0][pt][t1];
+  rate0 += mb->token_costs[tx_size][type][ref][band][0][ctx][t0];
+  rate1 += mb->token_costs[tx_size][type][ref][band][0][ctx][t1];
   UPDATE_RD_COST();
   best = rd_cost1 < rd_cost0;
-  final_eob = i0 - 1;
+  final_eob = -1;
   vpx_memset(qcoeff, 0, sizeof(*qcoeff) * (16 << (tx_size * 2)));
   vpx_memset(dqcoeff, 0, sizeof(*dqcoeff) * (16 << (tx_size * 2)));
   for (i = next; i < eob; i = next) {
-    x = tokens[i][best].qc;
+    const int x = tokens[i][best].qc;
+    const int rc = scan[i];
     if (x) {
       final_eob = i;
     }
-    rc = scan[i];
+
     qcoeff[rc] = x;
     dqcoeff[rc] = (x * dequant_ptr[rc != 0]) / mul;
 
@@ -303,7 +290,7 @@
   final_eob++;
 
   mb->plane[plane].eobs[block] = final_eob;
-  *a = *l = (final_eob > 0);
+  return final_eob;
 }
 
 static INLINE void fdct32x32(int rd_transform,
@@ -393,7 +380,8 @@
     vp9_xform_quant(x, plane, block, plane_bsize, tx_size);
 
   if (x->optimize && (!x->skip_recode || !x->skip_optimize)) {
-    optimize_b(plane, block, plane_bsize, tx_size, x, a, l);
+    const int ctx = combine_entropy_contexts(*a, *l);
+    *a = *l = optimize_b(x, plane, block, plane_bsize, tx_size, ctx) > 0;
   } else {
     *a = *l = p->eobs[block] > 0;
   }
@@ -485,7 +473,7 @@
   int16_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
   const scan_order *scan_order;
   TX_TYPE tx_type;
-  MB_PREDICTION_MODE mode;
+  PREDICTION_MODE mode;
   const int bwl = b_width_log2(plane_bsize);
   const int diff_stride = 4 * (1 << bwl);
   uint8_t *src, *dst;
@@ -613,15 +601,3 @@
   vp9_foreach_transformed_block_in_plane(xd, bsize, plane, encode_block_intra,
                                          &arg);
 }
-
-int vp9_encode_intra(MACROBLOCK *x, int use_16x16_pred) {
-  MB_MODE_INFO * mbmi = &x->e_mbd.mi[0]->mbmi;
-  x->skip_encode = 0;
-  mbmi->mode = DC_PRED;
-  mbmi->ref_frame[0] = INTRA_FRAME;
-  mbmi->tx_size = use_16x16_pred ? (mbmi->sb_type >= BLOCK_16X16 ? TX_16X16
-                                                                 : TX_8X8)
-                                   : TX_4X4;
-  vp9_encode_intra_block_plane(x, mbmi->sb_type, 0);
-  return vp9_get_mb_ss(x->plane[0].src_diff);
-}
diff --git a/vp9/encoder/vp9_encodemb.h b/vp9/encoder/vp9_encodemb.h
index dcf6e87..8021459 100644
--- a/vp9/encoder/vp9_encodemb.h
+++ b/vp9/encoder/vp9_encodemb.h
@@ -13,7 +13,7 @@
 
 #include "./vpx_config.h"
 #include "vp9/encoder/vp9_block.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/common/vp9_onyxc_int.h"
 
 #ifdef __cplusplus
@@ -34,8 +34,6 @@
 
 void vp9_encode_intra_block_plane(MACROBLOCK *x, BLOCK_SIZE bsize, int plane);
 
-int vp9_encode_intra(MACROBLOCK *x, int use_16x16_pred);
-
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/vp9/encoder/vp9_encodemv.h b/vp9/encoder/vp9_encodemv.h
index 50cb961..e67f9e3 100644
--- a/vp9/encoder/vp9_encodemv.h
+++ b/vp9/encoder/vp9_encodemv.h
@@ -12,7 +12,7 @@
 #ifndef VP9_ENCODER_VP9_ENCODEMV_H_
 #define VP9_ENCODER_VP9_ENCODEMV_H_
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_encoder.c
similarity index 80%
rename from vp9/encoder/vp9_onyx_if.c
rename to vp9/encoder/vp9_encoder.c
index 0ac9d5f..f3ab4ed 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -31,11 +31,12 @@
 #include "vp9/encoder/vp9_aq_cyclicrefresh.h"
 #include "vp9/encoder/vp9_aq_variance.h"
 #include "vp9/encoder/vp9_bitstream.h"
+#include "vp9/encoder/vp9_context_tree.h"
 #include "vp9/encoder/vp9_encodeframe.h"
 #include "vp9/encoder/vp9_encodemv.h"
 #include "vp9/encoder/vp9_firstpass.h"
 #include "vp9/encoder/vp9_mbgraph.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_picklpf.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 #include "vp9/encoder/vp9_rdopt.h"
@@ -61,11 +62,6 @@
                                          // now so that HIGH_PRECISION is always
                                          // chosen.
 
-// Max rate target for 1080P and below encodes under normal circumstances
-// (1920 * 1080 / (16 * 16)) * MAX_MB_RATE bits per MB
-#define MAX_MB_RATE 250
-#define MAXRATE_1080P 2025000
-
 // #define OUTPUT_YUV_REC
 
 #ifdef OUTPUT_YUV_SRC
@@ -135,6 +131,24 @@
   cm->fc = cm->frame_contexts[cm->frame_context_idx];
 }
 
+static void setup_frame(VP9_COMP *cpi) {
+  VP9_COMMON *const cm = &cpi->common;
+  // Set up entropy context depending on frame type. The decoder mandates
+  // the use of the default context, index 0, for keyframes and inter
+  // frames where the error_resilient_mode or intra_only flag is set. For
+  // other inter-frames the encoder currently uses only two contexts;
+  // context 1 for ALTREF frames and context 0 for the others.
+  if (cm->frame_type == KEY_FRAME) {
+    setup_key_frame(cpi);
+  } else {
+    if (!cm->intra_only && !cm->error_resilient_mode && !cpi->use_svc)
+        cm->frame_context_idx = cpi->refresh_alt_ref_frame;
+     setup_inter_frame(cm);
+  }
+}
+
+
+
 void vp9_initialize_enc() {
   static int init_done = 0;
 
@@ -148,6 +162,7 @@
     vp9_rc_init_minq_luts();
     vp9_entropy_mv_init();
     vp9_entropy_mode_init();
+    vp9_temporal_filter_init();
     init_done = 1;
   }
 }
@@ -184,11 +199,7 @@
   vpx_free(cpi->tok);
   cpi->tok = 0;
 
-  // Activity mask based per mb zbin adjustments
-  vpx_free(cpi->mb_activity_map);
-  cpi->mb_activity_map = 0;
-  vpx_free(cpi->mb_norm_activity_map);
-  cpi->mb_norm_activity_map = 0;
+  vp9_free_pc_tree(&cpi->mb);
 
   for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
     LAYER_CONTEXT *const lc = &cpi->svc.layer_context[i];
@@ -380,124 +391,7 @@
     cache_ptr += cm->mi_cols;
   }
 }
-static int is_slowest_mode(int mode) {
-  return (mode == MODE_SECONDPASS_BEST || mode == MODE_BESTQUALITY);
-}
 
-static void set_rd_speed_thresholds(VP9_COMP *cpi) {
-  int i;
-
-  // Set baseline threshold values
-  for (i = 0; i < MAX_MODES; ++i)
-  cpi->rd_thresh_mult[i] = is_slowest_mode(cpi->oxcf.mode) ? -500 : 0;
-
-  cpi->rd_thresh_mult[THR_NEARESTMV] = 0;
-  cpi->rd_thresh_mult[THR_NEARESTG] = 0;
-  cpi->rd_thresh_mult[THR_NEARESTA] = 0;
-
-  cpi->rd_thresh_mult[THR_DC] += 1000;
-
-  cpi->rd_thresh_mult[THR_NEWMV] += 1000;
-  cpi->rd_thresh_mult[THR_NEWA] += 1000;
-  cpi->rd_thresh_mult[THR_NEWG] += 1000;
-
-  cpi->rd_thresh_mult[THR_NEARMV] += 1000;
-  cpi->rd_thresh_mult[THR_NEARA] += 1000;
-  cpi->rd_thresh_mult[THR_COMP_NEARESTLA] += 1000;
-  cpi->rd_thresh_mult[THR_COMP_NEARESTGA] += 1000;
-
-  cpi->rd_thresh_mult[THR_TM] += 1000;
-
-  cpi->rd_thresh_mult[THR_COMP_NEARLA] += 1500;
-  cpi->rd_thresh_mult[THR_COMP_NEWLA] += 2000;
-  cpi->rd_thresh_mult[THR_NEARG] += 1000;
-  cpi->rd_thresh_mult[THR_COMP_NEARGA] += 1500;
-  cpi->rd_thresh_mult[THR_COMP_NEWGA] += 2000;
-
-  cpi->rd_thresh_mult[THR_ZEROMV] += 2000;
-  cpi->rd_thresh_mult[THR_ZEROG] += 2000;
-  cpi->rd_thresh_mult[THR_ZEROA] += 2000;
-  cpi->rd_thresh_mult[THR_COMP_ZEROLA] += 2500;
-  cpi->rd_thresh_mult[THR_COMP_ZEROGA] += 2500;
-
-  cpi->rd_thresh_mult[THR_H_PRED] += 2000;
-  cpi->rd_thresh_mult[THR_V_PRED] += 2000;
-  cpi->rd_thresh_mult[THR_D45_PRED ] += 2500;
-  cpi->rd_thresh_mult[THR_D135_PRED] += 2500;
-  cpi->rd_thresh_mult[THR_D117_PRED] += 2500;
-  cpi->rd_thresh_mult[THR_D153_PRED] += 2500;
-  cpi->rd_thresh_mult[THR_D207_PRED] += 2500;
-  cpi->rd_thresh_mult[THR_D63_PRED] += 2500;
-
-  /* disable frame modes if flags not set */
-  if (!(cpi->ref_frame_flags & VP9_LAST_FLAG)) {
-    cpi->rd_thresh_mult[THR_NEWMV    ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEARESTMV] = INT_MAX;
-    cpi->rd_thresh_mult[THR_ZEROMV   ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEARMV   ] = INT_MAX;
-  }
-  if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG)) {
-    cpi->rd_thresh_mult[THR_NEARESTG ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_ZEROG    ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEARG    ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEWG     ] = INT_MAX;
-  }
-  if (!(cpi->ref_frame_flags & VP9_ALT_FLAG)) {
-    cpi->rd_thresh_mult[THR_NEARESTA ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_ZEROA    ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEARA    ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_NEWA     ] = INT_MAX;
-  }
-
-  if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
-      (VP9_LAST_FLAG | VP9_ALT_FLAG)) {
-    cpi->rd_thresh_mult[THR_COMP_ZEROLA   ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEARESTLA] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEARLA   ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEWLA    ] = INT_MAX;
-  }
-  if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
-      (VP9_GOLD_FLAG | VP9_ALT_FLAG)) {
-    cpi->rd_thresh_mult[THR_COMP_ZEROGA   ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEARESTGA] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEARGA   ] = INT_MAX;
-    cpi->rd_thresh_mult[THR_COMP_NEWGA    ] = INT_MAX;
-  }
-}
-
-static void set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
-  const SPEED_FEATURES *const sf = &cpi->sf;
-  int i;
-
-  for (i = 0; i < MAX_REFS; ++i)
-    cpi->rd_thresh_mult_sub8x8[i] = is_slowest_mode(cpi->oxcf.mode)  ? -500 : 0;
-
-  cpi->rd_thresh_mult_sub8x8[THR_LAST] += 2500;
-  cpi->rd_thresh_mult_sub8x8[THR_GOLD] += 2500;
-  cpi->rd_thresh_mult_sub8x8[THR_ALTR] += 2500;
-  cpi->rd_thresh_mult_sub8x8[THR_INTRA] += 2500;
-  cpi->rd_thresh_mult_sub8x8[THR_COMP_LA] += 4500;
-  cpi->rd_thresh_mult_sub8x8[THR_COMP_GA] += 4500;
-
-  // Check for masked out split cases.
-  for (i = 0; i < MAX_REFS; i++)
-    if (sf->disable_split_mask & (1 << i))
-      cpi->rd_thresh_mult_sub8x8[i] = INT_MAX;
-
-  // disable mode test if frame flag is not set
-  if (!(cpi->ref_frame_flags & VP9_LAST_FLAG))
-    cpi->rd_thresh_mult_sub8x8[THR_LAST] = INT_MAX;
-  if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG))
-    cpi->rd_thresh_mult_sub8x8[THR_GOLD] = INT_MAX;
-  if (!(cpi->ref_frame_flags & VP9_ALT_FLAG))
-    cpi->rd_thresh_mult_sub8x8[THR_ALTR] = INT_MAX;
-  if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
-      (VP9_LAST_FLAG | VP9_ALT_FLAG))
-    cpi->rd_thresh_mult_sub8x8[THR_COMP_LA] = INT_MAX;
-  if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
-      (VP9_GOLD_FLAG | VP9_ALT_FLAG))
-    cpi->rd_thresh_mult_sub8x8[THR_COMP_GA] = INT_MAX;
-}
 
 static void set_speed_features(VP9_COMP *cpi) {
 #if CONFIG_INTERNAL_STATS
@@ -509,8 +403,8 @@
   vp9_set_speed_features(cpi);
 
   // Set rd thresholds based on mode and speed setting
-  set_rd_speed_thresholds(cpi);
-  set_rd_speed_thresholds_sub8x8(cpi);
+  vp9_set_rd_speed_thresholds(cpi);
+  vp9_set_rd_speed_thresholds_sub8x8(cpi);
 
   cpi->mb.fwd_txm4x4 = vp9_fdct4x4;
   if (cpi->oxcf.lossless || cpi->mb.e_mbd.lossless) {
@@ -520,7 +414,7 @@
 
 static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
   VP9_COMMON *cm = &cpi->common;
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
 
   cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height,
                                       cm->subsampling_x, cm->subsampling_y,
@@ -573,18 +467,9 @@
     CHECK_MEM_ERROR(cm, cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok)));
   }
 
-  vpx_free(cpi->mb_activity_map);
-  CHECK_MEM_ERROR(cm, cpi->mb_activity_map,
-                  vpx_calloc(sizeof(unsigned int),
-                             cm->mb_rows * cm->mb_cols));
-
-  vpx_free(cpi->mb_norm_activity_map);
-  CHECK_MEM_ERROR(cm, cpi->mb_norm_activity_map,
-                  vpx_calloc(sizeof(unsigned int),
-                             cm->mb_rows * cm->mb_cols));
+  vp9_setup_pc_tree(&cpi->common, &cpi->mb);
 }
 
-
 static void update_frame_size(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCKD *const xd = &cpi->mb.e_mbd;
@@ -617,9 +502,9 @@
     int y_stride = cpi->scaled_source.y_stride;
 
     if (cpi->sf.search_method == NSTEP) {
-      vp9_init3smotion_compensation(&cpi->mb, y_stride);
+      vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride);
     } else if (cpi->sf.search_method == DIAMOND) {
-      vp9_init_dsmotion_compensation(&cpi->mb, y_stride);
+      vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride);
     }
   }
 
@@ -627,50 +512,8 @@
 }
 
 void vp9_new_framerate(VP9_COMP *cpi, double framerate) {
-  VP9_COMMON *const cm = &cpi->common;
-  RATE_CONTROL *const rc = &cpi->rc;
-  VP9_CONFIG *const oxcf = &cpi->oxcf;
-  int vbr_max_bits;
-
-  oxcf->framerate = framerate < 0.1 ? 30 : framerate;
-  cpi->output_framerate = cpi->oxcf.framerate;
-  rc->av_per_frame_bandwidth = (int)(oxcf->target_bandwidth /
-                                     cpi->output_framerate);
-  rc->min_frame_bandwidth = (int)(rc->av_per_frame_bandwidth *
-                                  oxcf->two_pass_vbrmin_section / 100);
-
-  rc->min_frame_bandwidth = MAX(rc->min_frame_bandwidth, FRAME_OVERHEAD_BITS);
-
-  // A maximum bitrate for a frame is defined.
-  // The baseline for this aligns with HW implementations that
-  // can support decode of 1080P content up to a bitrate of MAX_MB_RATE bits
-  // per 16x16 MB (averaged over a frame). However this limit is extended if
-  // a very high rate is given on the command line or the the rate cannnot
-  // be acheived because of a user specificed max q (e.g. when the user
-  // specifies lossless encode.
-  //
-  vbr_max_bits = (int)(((int64_t)rc->av_per_frame_bandwidth *
-      oxcf->two_pass_vbrmax_section) / 100);
-  rc->max_frame_bandwidth = MAX(MAX((cm->MBs * MAX_MB_RATE), MAXRATE_1080P),
-                                vbr_max_bits);
-
-  // Set Maximum gf/arf interval
-  rc->max_gf_interval = 16;
-
-  // Extended interval for genuinely static scenes
-  rc->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;
-
-  // Special conditions when alt ref frame enabled in lagged compress mode
-  if (oxcf->play_alternate && oxcf->lag_in_frames) {
-    if (rc->max_gf_interval > oxcf->lag_in_frames - 1)
-      rc->max_gf_interval = oxcf->lag_in_frames - 1;
-
-    if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
-      rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
-  }
-
-  if (rc->max_gf_interval > rc->static_scene_max_gf_interval)
-    rc->max_gf_interval = rc->static_scene_max_gf_interval;
+  cpi->oxcf.framerate = framerate < 0.1 ? 30 : framerate;
+  vp9_rc_update_framerate(cpi);
 }
 
 int64_t vp9_rescale(int64_t val, int64_t num, int denom) {
@@ -692,9 +535,8 @@
   cm->log2_tile_rows = cpi->oxcf.tile_rows;
 }
 
-static void init_config(struct VP9_COMP *cpi, VP9_CONFIG *oxcf) {
+static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) {
   VP9_COMMON *const cm = &cpi->common;
-  int i;
 
   cpi->oxcf = *oxcf;
 
@@ -713,9 +555,9 @@
   cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
 
   if ((cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+      cpi->oxcf.rc_mode == RC_MODE_CBR) ||
       (cpi->svc.number_spatial_layers > 1 &&
-      cpi->oxcf.mode == MODE_SECONDPASS_BEST)) {
+      cpi->oxcf.mode == TWO_PASS_SECOND_BEST)) {
     vp9_init_layer_context(cpi);
   }
 
@@ -729,13 +571,26 @@
   cpi->alt_fb_idx = 2;
 
   set_tile_limits(cpi);
-
-  cpi->fixed_divide[0] = 0;
-  for (i = 1; i < 512; i++)
-    cpi->fixed_divide[i] = 0x80000 / i;
 }
 
-void vp9_change_config(struct VP9_COMP *cpi, const VP9_CONFIG *oxcf) {
+static int get_pass(MODE mode) {
+  switch (mode) {
+    case REALTIME:
+    case ONE_PASS_GOOD:
+    case ONE_PASS_BEST:
+      return 0;
+
+    case TWO_PASS_FIRST:
+      return 1;
+
+    case TWO_PASS_SECOND_GOOD:
+    case TWO_PASS_SECOND_BEST:
+      return 2;
+  }
+  return -1;
+}
+
+void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
 
@@ -749,39 +604,10 @@
     assert(cm->bit_depth > BITS_8);
 
   cpi->oxcf = *oxcf;
-
-  if (cpi->oxcf.cpu_used == -6)
+  cpi->pass = get_pass(cpi->oxcf.mode);
+  if (cpi->oxcf.mode == REALTIME)
     cpi->oxcf.play_alternate = 0;
 
-  switch (cpi->oxcf.mode) {
-      // Real time and one pass deprecated in test code base
-    case MODE_GOODQUALITY:
-      cpi->pass = 0;
-      cpi->oxcf.cpu_used = clamp(cpi->oxcf.cpu_used, -5, 5);
-      break;
-
-    case MODE_BESTQUALITY:
-      cpi->pass = 0;
-      break;
-
-    case MODE_FIRSTPASS:
-      cpi->pass = 1;
-      break;
-
-    case MODE_SECONDPASS:
-      cpi->pass = 2;
-      cpi->oxcf.cpu_used = clamp(cpi->oxcf.cpu_used, -5, 5);
-      break;
-
-    case MODE_SECONDPASS_BEST:
-      cpi->pass = 2;
-      break;
-
-    case MODE_REALTIME:
-      cpi->pass = 0;
-      break;
-  }
-
   cpi->oxcf.lossless = oxcf->lossless;
   if (cpi->oxcf.lossless) {
     // In lossless mode, make sure right quantizer range and correct transform
@@ -812,7 +638,7 @@
   cpi->encode_breakout = cpi->oxcf.encode_breakout;
 
   // local file playback mode == really big buffer
-  if (cpi->oxcf.end_usage == USAGE_LOCAL_FILE_PLAYBACK) {
+  if (cpi->oxcf.rc_mode == RC_MODE_VBR) {
     cpi->oxcf.starting_buffer_level   = 60000;
     cpi->oxcf.optimal_buffer_level    = 60000;
     cpi->oxcf.maximum_buffer_size     = 240000;
@@ -851,20 +677,11 @@
   rc->worst_quality = cpi->oxcf.worst_allowed_q;
   rc->best_quality = cpi->oxcf.best_allowed_q;
 
-  // active values should only be modified if out of new range
-
-  cpi->cq_target_quality = cpi->oxcf.cq_level;
-
   cm->interp_filter = DEFAULT_INTERP_FILTER;
 
   cm->display_width = cpi->oxcf.width;
   cm->display_height = cpi->oxcf.height;
 
-  // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs)
-  cpi->oxcf.sharpness = MIN(7, cpi->oxcf.sharpness);
-
-  cpi->common.lf.sharpness_level = cpi->oxcf.sharpness;
-
   if (cpi->initial_width) {
     // Increasing the size of the frame beyond the first seen frame, or some
     // otherwise signaled maximum size, is not supported.
@@ -875,18 +692,12 @@
   update_frame_size(cpi);
 
   if ((cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+      cpi->oxcf.rc_mode == RC_MODE_CBR) ||
       (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
     vp9_update_layer_context_change_config(cpi,
                                            (int)cpi->oxcf.target_bandwidth);
   }
 
-  cpi->speed = abs(cpi->oxcf.cpu_used);
-
-  // Limit on lag buffers as these are not currently dynamically allocated.
-  if (cpi->oxcf.lag_in_frames > MAX_LAG_BUFFERS)
-    cpi->oxcf.lag_in_frames = MAX_LAG_BUFFERS;
-
 #if CONFIG_MULTIPLE_ARF
   vp9_zero(cpi->alt_ref_source);
 #else
@@ -906,7 +717,9 @@
   cpi->ext_refresh_frame_context_pending = 0;
 }
 
+#ifndef M_LOG2_E
 #define M_LOG2_E 0.693147180559945309417
+#endif
 #define log2f(x) (log (x) / (float) M_LOG2_E)
 
 static void cal_nmvjointsadcost(int *mvjointsadcost) {
@@ -946,126 +759,8 @@
   } while (++i <= MV_MAX);
 }
 
-static void alloc_mode_context(VP9_COMMON *cm, int num_4x4_blk,
-                               PICK_MODE_CONTEXT *ctx) {
-  int num_pix = num_4x4_blk << 4;
-  int i, k;
-  ctx->num_4x4_blk = num_4x4_blk;
 
-  CHECK_MEM_ERROR(cm, ctx->zcoeff_blk,
-                  vpx_calloc(num_4x4_blk, sizeof(uint8_t)));
-  for (i = 0; i < MAX_MB_PLANE; ++i) {
-    for (k = 0; k < 3; ++k) {
-      CHECK_MEM_ERROR(cm, ctx->coeff[i][k],
-                      vpx_memalign(16, num_pix * sizeof(int16_t)));
-      CHECK_MEM_ERROR(cm, ctx->qcoeff[i][k],
-                      vpx_memalign(16, num_pix * sizeof(int16_t)));
-      CHECK_MEM_ERROR(cm, ctx->dqcoeff[i][k],
-                      vpx_memalign(16, num_pix * sizeof(int16_t)));
-      CHECK_MEM_ERROR(cm, ctx->eobs[i][k],
-                      vpx_memalign(16, num_pix * sizeof(uint16_t)));
-      ctx->coeff_pbuf[i][k]   = ctx->coeff[i][k];
-      ctx->qcoeff_pbuf[i][k]  = ctx->qcoeff[i][k];
-      ctx->dqcoeff_pbuf[i][k] = ctx->dqcoeff[i][k];
-      ctx->eobs_pbuf[i][k]    = ctx->eobs[i][k];
-    }
-  }
-}
-
-static void free_mode_context(PICK_MODE_CONTEXT *ctx) {
-  int i, k;
-  vpx_free(ctx->zcoeff_blk);
-  ctx->zcoeff_blk = 0;
-  for (i = 0; i < MAX_MB_PLANE; ++i) {
-    for (k = 0; k < 3; ++k) {
-      vpx_free(ctx->coeff[i][k]);
-      ctx->coeff[i][k] = 0;
-      vpx_free(ctx->qcoeff[i][k]);
-      ctx->qcoeff[i][k] = 0;
-      vpx_free(ctx->dqcoeff[i][k]);
-      ctx->dqcoeff[i][k] = 0;
-      vpx_free(ctx->eobs[i][k]);
-      ctx->eobs[i][k] = 0;
-    }
-  }
-}
-
-static void init_pick_mode_context(VP9_COMP *cpi) {
-  int i;
-  VP9_COMMON *const cm = &cpi->common;
-  MACROBLOCK *const x  = &cpi->mb;
-
-  for (i = 0; i < BLOCK_SIZES; ++i) {
-    const int num_4x4_w = num_4x4_blocks_wide_lookup[i];
-    const int num_4x4_h = num_4x4_blocks_high_lookup[i];
-    const int num_4x4_blk = MAX(4, num_4x4_w * num_4x4_h);
-    if (i < BLOCK_16X16) {
-      for (x->sb_index = 0; x->sb_index < 4; ++x->sb_index) {
-        for (x->mb_index = 0; x->mb_index < 4; ++x->mb_index) {
-          for (x->b_index = 0; x->b_index < 16 / num_4x4_blk; ++x->b_index) {
-            PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-            alloc_mode_context(cm, num_4x4_blk, ctx);
-          }
-        }
-      }
-    } else if (i < BLOCK_32X32) {
-      for (x->sb_index = 0; x->sb_index < 4; ++x->sb_index) {
-        for (x->mb_index = 0; x->mb_index < 64 / num_4x4_blk; ++x->mb_index) {
-          PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-          ctx->num_4x4_blk = num_4x4_blk;
-          alloc_mode_context(cm, num_4x4_blk, ctx);
-        }
-      }
-    } else if (i < BLOCK_64X64) {
-      for (x->sb_index = 0; x->sb_index < 256 / num_4x4_blk; ++x->sb_index) {
-        PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-        ctx->num_4x4_blk = num_4x4_blk;
-        alloc_mode_context(cm, num_4x4_blk, ctx);
-      }
-    } else {
-      PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-      ctx->num_4x4_blk = num_4x4_blk;
-      alloc_mode_context(cm, num_4x4_blk, ctx);
-    }
-  }
-}
-
-static void free_pick_mode_context(MACROBLOCK *x) {
-  int i;
-
-  for (i = 0; i < BLOCK_SIZES; ++i) {
-    const int num_4x4_w = num_4x4_blocks_wide_lookup[i];
-    const int num_4x4_h = num_4x4_blocks_high_lookup[i];
-    const int num_4x4_blk = MAX(4, num_4x4_w * num_4x4_h);
-    if (i < BLOCK_16X16) {
-      for (x->sb_index = 0; x->sb_index < 4; ++x->sb_index) {
-        for (x->mb_index = 0; x->mb_index < 4; ++x->mb_index) {
-          for (x->b_index = 0; x->b_index < 16 / num_4x4_blk; ++x->b_index) {
-            PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-            free_mode_context(ctx);
-          }
-        }
-      }
-    } else if (i < BLOCK_32X32) {
-      for (x->sb_index = 0; x->sb_index < 4; ++x->sb_index) {
-        for (x->mb_index = 0; x->mb_index < 64 / num_4x4_blk; ++x->mb_index) {
-          PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-          free_mode_context(ctx);
-        }
-      }
-    } else if (i < BLOCK_64X64) {
-      for (x->sb_index = 0; x->sb_index < 256 / num_4x4_blk; ++x->sb_index) {
-        PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-        free_mode_context(ctx);
-      }
-    } else {
-      PICK_MODE_CONTEXT *ctx = get_block_context(x, i);
-      free_mode_context(ctx);
-    }
-  }
-}
-
-VP9_COMP *vp9_create_compressor(VP9_CONFIG *oxcf) {
+VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf) {
   int i, j;
   VP9_COMP *const cpi = vpx_memalign(32, sizeof(VP9_COMP));
   VP9_COMMON *const cm = cpi != NULL ? &cpi->common : NULL;
@@ -1083,16 +778,12 @@
 
   cm->error.setjmp = 1;
 
-  CHECK_MEM_ERROR(cm, cpi->mb.ss, vpx_calloc(sizeof(search_site),
-                                             (MAX_MVSEARCH_STEPS * 8) + 1));
-
   vp9_rtcd();
 
   cpi->use_svc = 0;
 
   init_config(cpi, oxcf);
   vp9_rc_init(&cpi->oxcf, cpi->pass, &cpi->rc);
-  init_pick_mode_context(cpi);
 
   cm->current_video_frame = 0;
 
@@ -1131,9 +822,6 @@
                                sizeof(*cpi->mbgraph_stats[i].mb_stats), 1));
   }
 
-  /*Initialize the feed-forward activity masking.*/
-  cpi->activity_avg = 90 << 12;
-  cpi->key_frame_frequency = cpi->oxcf.key_freq;
   cpi->refresh_alt_ref_frame = 0;
 
 #if CONFIG_MULTIPLE_ARF
@@ -1275,100 +963,76 @@
   // Default rd threshold factors for mode selection
   for (i = 0; i < BLOCK_SIZES; ++i) {
     for (j = 0; j < MAX_MODES; ++j)
-      cpi->rd_thresh_freq_fact[i][j] = 32;
-    for (j = 0; j < MAX_REFS; ++j)
-      cpi->rd_thresh_freq_sub8x8[i][j] = 32;
+      cpi->rd.thresh_freq_fact[i][j] = 32;
   }
 
-#define BFP(BT, SDF, SDAF, VF, SVF, SVAF, SVFHH, SVFHV, SVFHHV, \
-            SDX3F, SDX8F, SDX4DF)\
+#define BFP(BT, SDF, SDAF, VF, SVF, SVAF, SDX3F, SDX8F, SDX4DF)\
     cpi->fn_ptr[BT].sdf            = SDF; \
     cpi->fn_ptr[BT].sdaf           = SDAF; \
     cpi->fn_ptr[BT].vf             = VF; \
     cpi->fn_ptr[BT].svf            = SVF; \
     cpi->fn_ptr[BT].svaf           = SVAF; \
-    cpi->fn_ptr[BT].svf_halfpix_h  = SVFHH; \
-    cpi->fn_ptr[BT].svf_halfpix_v  = SVFHV; \
-    cpi->fn_ptr[BT].svf_halfpix_hv = SVFHHV; \
     cpi->fn_ptr[BT].sdx3f          = SDX3F; \
     cpi->fn_ptr[BT].sdx8f          = SDX8F; \
     cpi->fn_ptr[BT].sdx4df         = SDX4DF;
 
   BFP(BLOCK_32X16, vp9_sad32x16, vp9_sad32x16_avg,
       vp9_variance32x16, vp9_sub_pixel_variance32x16,
-      vp9_sub_pixel_avg_variance32x16, NULL, NULL,
-      NULL, NULL, NULL,
-      vp9_sad32x16x4d)
+      vp9_sub_pixel_avg_variance32x16, NULL, NULL, vp9_sad32x16x4d)
 
   BFP(BLOCK_16X32, vp9_sad16x32, vp9_sad16x32_avg,
       vp9_variance16x32, vp9_sub_pixel_variance16x32,
-      vp9_sub_pixel_avg_variance16x32, NULL, NULL,
-      NULL, NULL, NULL,
-      vp9_sad16x32x4d)
+      vp9_sub_pixel_avg_variance16x32, NULL, NULL, vp9_sad16x32x4d)
 
   BFP(BLOCK_64X32, vp9_sad64x32, vp9_sad64x32_avg,
       vp9_variance64x32, vp9_sub_pixel_variance64x32,
-      vp9_sub_pixel_avg_variance64x32, NULL, NULL,
-      NULL, NULL, NULL,
-      vp9_sad64x32x4d)
+      vp9_sub_pixel_avg_variance64x32, NULL, NULL, vp9_sad64x32x4d)
 
   BFP(BLOCK_32X64, vp9_sad32x64, vp9_sad32x64_avg,
       vp9_variance32x64, vp9_sub_pixel_variance32x64,
-      vp9_sub_pixel_avg_variance32x64, NULL, NULL,
-      NULL, NULL, NULL,
-      vp9_sad32x64x4d)
+      vp9_sub_pixel_avg_variance32x64, NULL, NULL, vp9_sad32x64x4d)
 
   BFP(BLOCK_32X32, vp9_sad32x32, vp9_sad32x32_avg,
       vp9_variance32x32, vp9_sub_pixel_variance32x32,
-      vp9_sub_pixel_avg_variance32x32, vp9_variance_halfpixvar32x32_h,
-      vp9_variance_halfpixvar32x32_v,
-      vp9_variance_halfpixvar32x32_hv, vp9_sad32x32x3, vp9_sad32x32x8,
+      vp9_sub_pixel_avg_variance32x32, vp9_sad32x32x3, vp9_sad32x32x8,
       vp9_sad32x32x4d)
 
   BFP(BLOCK_64X64, vp9_sad64x64, vp9_sad64x64_avg,
       vp9_variance64x64, vp9_sub_pixel_variance64x64,
-      vp9_sub_pixel_avg_variance64x64, vp9_variance_halfpixvar64x64_h,
-      vp9_variance_halfpixvar64x64_v,
-      vp9_variance_halfpixvar64x64_hv, vp9_sad64x64x3, vp9_sad64x64x8,
+      vp9_sub_pixel_avg_variance64x64, vp9_sad64x64x3, vp9_sad64x64x8,
       vp9_sad64x64x4d)
 
   BFP(BLOCK_16X16, vp9_sad16x16, vp9_sad16x16_avg,
       vp9_variance16x16, vp9_sub_pixel_variance16x16,
-      vp9_sub_pixel_avg_variance16x16, vp9_variance_halfpixvar16x16_h,
-      vp9_variance_halfpixvar16x16_v,
-      vp9_variance_halfpixvar16x16_hv, vp9_sad16x16x3, vp9_sad16x16x8,
+      vp9_sub_pixel_avg_variance16x16, vp9_sad16x16x3, vp9_sad16x16x8,
       vp9_sad16x16x4d)
 
   BFP(BLOCK_16X8, vp9_sad16x8, vp9_sad16x8_avg,
       vp9_variance16x8, vp9_sub_pixel_variance16x8,
-      vp9_sub_pixel_avg_variance16x8, NULL, NULL, NULL,
+      vp9_sub_pixel_avg_variance16x8,
       vp9_sad16x8x3, vp9_sad16x8x8, vp9_sad16x8x4d)
 
   BFP(BLOCK_8X16, vp9_sad8x16, vp9_sad8x16_avg,
       vp9_variance8x16, vp9_sub_pixel_variance8x16,
-      vp9_sub_pixel_avg_variance8x16, NULL, NULL, NULL,
+      vp9_sub_pixel_avg_variance8x16,
       vp9_sad8x16x3, vp9_sad8x16x8, vp9_sad8x16x4d)
 
   BFP(BLOCK_8X8, vp9_sad8x8, vp9_sad8x8_avg,
       vp9_variance8x8, vp9_sub_pixel_variance8x8,
-      vp9_sub_pixel_avg_variance8x8, NULL, NULL, NULL,
+      vp9_sub_pixel_avg_variance8x8,
       vp9_sad8x8x3, vp9_sad8x8x8, vp9_sad8x8x4d)
 
   BFP(BLOCK_8X4, vp9_sad8x4, vp9_sad8x4_avg,
       vp9_variance8x4, vp9_sub_pixel_variance8x4,
-      vp9_sub_pixel_avg_variance8x4, NULL, NULL,
-      NULL, NULL, vp9_sad8x4x8,
-      vp9_sad8x4x4d)
+      vp9_sub_pixel_avg_variance8x4, NULL, vp9_sad8x4x8, vp9_sad8x4x4d)
 
   BFP(BLOCK_4X8, vp9_sad4x8, vp9_sad4x8_avg,
       vp9_variance4x8, vp9_sub_pixel_variance4x8,
-      vp9_sub_pixel_avg_variance4x8, NULL, NULL,
-      NULL, NULL, vp9_sad4x8x8,
-      vp9_sad4x8x4d)
+      vp9_sub_pixel_avg_variance4x8, NULL, vp9_sad4x8x8, vp9_sad4x8x4d)
 
   BFP(BLOCK_4X4, vp9_sad4x4, vp9_sad4x4_avg,
       vp9_variance4x4, vp9_sub_pixel_variance4x4,
-      vp9_sub_pixel_avg_variance4x4, NULL, NULL, NULL,
+      vp9_sub_pixel_avg_variance4x4,
       vp9_sad4x4x3, vp9_sad4x4x8, vp9_sad4x4x4d)
 
   cpi->full_search_sad = vp9_full_search_sad;
@@ -1386,8 +1050,6 @@
 
   cm->error.setjmp = 0;
 
-  vp9_zero(cpi->common.counts.uv_mode);
-
 #ifdef MODE_TEST_HIT_STATS
   vp9_zero(cpi->mode_test_hits);
 #endif
@@ -1490,9 +1152,7 @@
 #endif
   }
 
-  free_pick_mode_context(&cpi->mb);
   dealloc_compressor_data(cpi);
-  vpx_free(cpi->mb.ss);
   vpx_free(cpi->tok);
 
   for (i = 0; i < sizeof(cpi->mbgraph_stats) /
@@ -1754,81 +1414,75 @@
 }
 #endif
 
-static void scale_and_extend_frame_nonnormative(YV12_BUFFER_CONFIG *src_fb,
-                                                YV12_BUFFER_CONFIG *dst_fb) {
-  const int in_w = src_fb->y_crop_width;
-  const int in_h = src_fb->y_crop_height;
-  const int out_w = dst_fb->y_crop_width;
-  const int out_h = dst_fb->y_crop_height;
-  const int in_w_uv = src_fb->uv_crop_width;
-  const int in_h_uv = src_fb->uv_crop_height;
-  const int out_w_uv = dst_fb->uv_crop_width;
-  const int out_h_uv = dst_fb->uv_crop_height;
+static void scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
+                                                YV12_BUFFER_CONFIG *dst) {
+  // TODO(dkovalev): replace YV12_BUFFER_CONFIG with vpx_image_t
   int i;
+  const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
+                                  src->alpha_buffer};
+  const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
+                              src->alpha_stride};
+  const int src_widths[4] = {src->y_crop_width, src->uv_crop_width,
+                             src->uv_crop_width, src->y_crop_width};
+  const int src_heights[4] = {src->y_crop_height, src->uv_crop_height,
+                              src->uv_crop_height, src->y_crop_height};
+  uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
+                            dst->alpha_buffer};
+  const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
+                              dst->alpha_stride};
+  const int dst_widths[4] = {dst->y_crop_width, dst->uv_crop_width,
+                             dst->uv_crop_width, dst->y_crop_width};
+  const int dst_heights[4] = {dst->y_crop_height, dst->uv_crop_height,
+                              dst->uv_crop_height, dst->y_crop_height};
 
-  uint8_t *srcs[4] = {src_fb->y_buffer, src_fb->u_buffer, src_fb->v_buffer,
-    src_fb->alpha_buffer};
-  int src_strides[4] = {src_fb->y_stride, src_fb->uv_stride, src_fb->uv_stride,
-    src_fb->alpha_stride};
+  for (i = 0; i < MAX_MB_PLANE; ++i)
+    vp9_resize_plane(srcs[i], src_heights[i], src_widths[i], src_strides[i],
+                     dsts[i], dst_heights[i], dst_widths[i], dst_strides[i]);
 
-  uint8_t *dsts[4] = {dst_fb->y_buffer, dst_fb->u_buffer, dst_fb->v_buffer,
-    dst_fb->alpha_buffer};
-  int dst_strides[4] = {dst_fb->y_stride, dst_fb->uv_stride, dst_fb->uv_stride,
-    dst_fb->alpha_stride};
-
-  for (i = 0; i < MAX_MB_PLANE; ++i) {
-    if (i == 0 || i == 3) {
-      // Y and alpha planes
-      vp9_resize_plane(srcs[i], in_h, in_w, src_strides[i],
-                       dsts[i], out_h, out_w, dst_strides[i]);
-    } else {
-      // Chroma planes
-      vp9_resize_plane(srcs[i], in_h_uv, in_w_uv, src_strides[i],
-                       dsts[i], out_h_uv, out_w_uv, dst_strides[i]);
-    }
-  }
-  vp8_yv12_extend_frame_borders(dst_fb);
+  // TODO(hkuang): Call C version explicitly
+  // as neon version only expand border size 32.
+  vp8_yv12_extend_frame_borders_c(dst);
 }
 
-static void scale_and_extend_frame(YV12_BUFFER_CONFIG *src_fb,
-                                   YV12_BUFFER_CONFIG *dst_fb) {
-  const int in_w = src_fb->y_crop_width;
-  const int in_h = src_fb->y_crop_height;
-  const int out_w = dst_fb->y_crop_width;
-  const int out_h = dst_fb->y_crop_height;
+static void scale_and_extend_frame(const YV12_BUFFER_CONFIG *src,
+                                   YV12_BUFFER_CONFIG *dst) {
+  const int src_w = src->y_crop_width;
+  const int src_h = src->y_crop_height;
+  const int dst_w = dst->y_crop_width;
+  const int dst_h = dst->y_crop_height;
+  const uint8_t *const srcs[4] = {src->y_buffer, src->u_buffer, src->v_buffer,
+                                  src->alpha_buffer};
+  const int src_strides[4] = {src->y_stride, src->uv_stride, src->uv_stride,
+                              src->alpha_stride};
+  uint8_t *const dsts[4] = {dst->y_buffer, dst->u_buffer, dst->v_buffer,
+                            dst->alpha_buffer};
+  const int dst_strides[4] = {dst->y_stride, dst->uv_stride, dst->uv_stride,
+                              dst->alpha_stride};
   int x, y, i;
 
-  uint8_t *srcs[4] = {src_fb->y_buffer, src_fb->u_buffer, src_fb->v_buffer,
-                      src_fb->alpha_buffer};
-  int src_strides[4] = {src_fb->y_stride, src_fb->uv_stride, src_fb->uv_stride,
-                        src_fb->alpha_stride};
-
-  uint8_t *dsts[4] = {dst_fb->y_buffer, dst_fb->u_buffer, dst_fb->v_buffer,
-                      dst_fb->alpha_buffer};
-  int dst_strides[4] = {dst_fb->y_stride, dst_fb->uv_stride, dst_fb->uv_stride,
-                        dst_fb->alpha_stride};
-
-  for (y = 0; y < out_h; y += 16) {
-    for (x = 0; x < out_w; x += 16) {
+  for (y = 0; y < dst_h; y += 16) {
+    for (x = 0; x < dst_w; x += 16) {
       for (i = 0; i < MAX_MB_PLANE; ++i) {
         const int factor = (i == 0 || i == 3 ? 1 : 2);
-        const int x_q4 = x * (16 / factor) * in_w / out_w;
-        const int y_q4 = y * (16 / factor) * in_h / out_h;
+        const int x_q4 = x * (16 / factor) * src_w / dst_w;
+        const int y_q4 = y * (16 / factor) * src_h / dst_h;
         const int src_stride = src_strides[i];
         const int dst_stride = dst_strides[i];
-        uint8_t *src = srcs[i] + y / factor * in_h / out_h * src_stride +
-                                 x / factor * in_w / out_w;
-        uint8_t *dst = dsts[i] + y / factor * dst_stride + x / factor;
+        const uint8_t *src_ptr = srcs[i] + (y / factor) * src_h / dst_h *
+                                     src_stride + (x / factor) * src_w / dst_w;
+        uint8_t *dst_ptr = dsts[i] + (y / factor) * dst_stride + (x / factor);
 
-        vp9_convolve8(src, src_stride, dst, dst_stride,
-                      vp9_sub_pel_filters_8[x_q4 & 0xf], 16 * in_w / out_w,
-                      vp9_sub_pel_filters_8[y_q4 & 0xf], 16 * in_h / out_h,
+        vp9_convolve8(src_ptr, src_stride, dst_ptr, dst_stride,
+                      vp9_sub_pel_filters_8[x_q4 & 0xf], 16 * src_w / dst_w,
+                      vp9_sub_pel_filters_8[y_q4 & 0xf], 16 * src_h / dst_h,
                       16 / factor, 16 / factor);
       }
     }
   }
 
-  vp8_yv12_extend_frame_borders(dst_fb);
+  // TODO(hkuang): Call C version explicitly
+  // as neon version only expand border size 32.
+  vp8_yv12_extend_frame_borders_c(dst);
 }
 
 static int find_fp_qindex() {
@@ -1887,6 +1541,7 @@
                             int q, int maxq, int minq) {
   const VP9_COMMON *const cm = &cpi->common;
   const RATE_CONTROL *const rc = &cpi->rc;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   int force_recode = 0;
 
   // Special case trap if maximum allowed frame size exceeded.
@@ -1904,10 +1559,10 @@
     if ((rc->projected_frame_size > high_limit && q < maxq) ||
         (rc->projected_frame_size < low_limit && q > minq)) {
       force_recode = 1;
-    } else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) {
+    } else if (cpi->oxcf.rc_mode == RC_MODE_CONSTRAINED_QUALITY) {
       // Deal with frame undershoot and whether or not we are
       // below the automatically set cq level.
-      if (q > cpi->cq_target_quality &&
+      if (q > oxcf->cq_level &&
           rc->projected_frame_size < ((rc->this_frame_target * 7) >> 3)) {
         force_recode = 1;
       }
@@ -2006,7 +1661,7 @@
 
   for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
     const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
-    YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf;
+    const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf;
 
     if (ref->y_crop_width != cm->width ||
         ref->y_crop_height != cm->height) {
@@ -2065,8 +1720,8 @@
   recon_err = vp9_get_y_sse(cpi->Source, get_frame_new_buffer(cm));
 
   if (cpi->twopass.total_left_stats.coded_error != 0.0)
-    fprintf(f, "%10u %10d %10d %10d %10d %10d "
-        "%10"PRId64" %10"PRId64" %10d "
+    fprintf(f, "%10u %10d %10d %10d %10d"
+        "%10"PRId64" %10"PRId64" %10"PRId64" %10"PRId64" %10d "
         "%7.2lf %7.2lf %7.2lf %7.2lf %7.2lf"
         "%6d %6d %5d %5d %5d "
         "%10"PRId64" %10.3lf"
@@ -2075,6 +1730,7 @@
         cpi->rc.projected_frame_size,
         cpi->rc.projected_frame_size / cpi->common.MBs,
         (cpi->rc.projected_frame_size - cpi->rc.this_frame_target),
+        cpi->rc.vbr_bits_off_target,
         cpi->rc.total_target_vs_actual,
         (cpi->oxcf.starting_buffer_level - cpi->rc.bits_off_target),
         cpi->rc.total_actual_bits, cm->base_qindex,
@@ -2082,7 +1738,7 @@
         (double)vp9_dc_quant(cm->base_qindex, 0) / 4.0,
         cpi->rc.avg_q,
         vp9_convert_qindex_to_q(cpi->rc.ni_av_qi),
-        vp9_convert_qindex_to_q(cpi->cq_target_quality),
+        vp9_convert_qindex_to_q(cpi->oxcf.cq_level),
         cpi->refresh_last_frame, cpi->refresh_golden_frame,
         cpi->refresh_alt_ref_frame, cm->frame_type, cpi->rc.gfu_boost,
         cpi->twopass.bits_left,
@@ -2119,20 +1775,7 @@
   VP9_COMMON *const cm = &cpi->common;
   vp9_clear_system_state();
   vp9_set_quantizer(cm, q);
-
-  // Set up entropy context depending on frame type. The decoder mandates
-  // the use of the default context, index 0, for keyframes and inter
-  // frames where the error_resilient_mode or intra_only flag is set. For
-  // other inter-frames the encoder currently uses only two contexts;
-  // context 1 for ALTREF frames and context 0 for the others.
-  if (cm->frame_type == KEY_FRAME) {
-    setup_key_frame(cpi);
-  } else {
-    if (!cm->intra_only && !cm->error_resilient_mode && !cpi->use_svc)
-      cm->frame_context_idx = cpi->refresh_alt_ref_frame;
-
-    setup_inter_frame(cm);
-  }
+  setup_frame(cpi);
   // Variance adaptive and in frame q adjustment experiments are mutually
   // exclusive.
   if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
@@ -2177,21 +1820,8 @@
 
     vp9_set_quantizer(cm, q);
 
-    if (loop_count == 0) {
-      // Set up entropy context depending on frame type. The decoder mandates
-      // the use of the default context, index 0, for keyframes and inter
-      // frames where the error_resilient_mode or intra_only flag is set. For
-      // other inter-frames the encoder currently uses only two contexts;
-      // context 1 for ALTREF frames and context 0 for the others.
-      if (cm->frame_type == KEY_FRAME) {
-        setup_key_frame(cpi);
-      } else {
-        if (!cm->intra_only && !cm->error_resilient_mode && !cpi->use_svc)
-          cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame;
-
-        setup_inter_frame(cm);
-      }
-    }
+    if (loop_count == 0)
+      setup_frame(cpi);
 
     // Variance adaptive and in frame q adjustment experiments are mutually
     // exclusive.
@@ -2226,7 +1856,7 @@
         frame_over_shoot_limit = 1;
     }
 
-    if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
+    if (cpi->oxcf.rc_mode == RC_MODE_CONSTANT_QUALITY) {
       loop = 0;
     } else {
       if ((cm->frame_type == KEY_FRAME) &&
@@ -2324,7 +1954,7 @@
             // This should only trigger where there is very substantial
             // undershoot on a frame and the auto cq level is above
             // the user passsed in value.
-            if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY &&
+            if (cpi->oxcf.rc_mode == RC_MODE_CONSTRAINED_QUALITY &&
                 q < q_low) {
               q_low = q;
             }
@@ -2412,6 +2042,18 @@
   }
 }
 
+YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
+                                          YV12_BUFFER_CONFIG *unscaled,
+                                          YV12_BUFFER_CONFIG *scaled) {
+  if (cm->mi_cols * MI_SIZE != unscaled->y_width ||
+      cm->mi_rows * MI_SIZE != unscaled->y_height) {
+    scale_and_extend_frame_nonnormative(unscaled, scaled);
+    return scaled;
+  } else {
+    return unscaled;
+  }
+}
+
 static void encode_frame_to_data_rate(VP9_COMP *cpi,
                                       size_t *size,
                                       uint8_t *dest,
@@ -2425,30 +2067,14 @@
   const SPEED_FEATURES *const sf = &cpi->sf;
   const unsigned int max_mv_def = MIN(cm->width, cm->height);
   struct segmentation *const seg = &cm->seg;
-
   set_ext_overrides(cpi);
 
-  /* Scale the source buffer, if required. */
-  if (cm->mi_cols * MI_SIZE != cpi->un_scaled_source->y_width ||
-      cm->mi_rows * MI_SIZE != cpi->un_scaled_source->y_height) {
-    scale_and_extend_frame_nonnormative(cpi->un_scaled_source,
-                                        &cpi->scaled_source);
-    cpi->Source = &cpi->scaled_source;
-  } else {
-    cpi->Source = cpi->un_scaled_source;
-  }
+  cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
+                                      &cpi->scaled_source);
 
-  // Scale the last source buffer, if required.
-  if (cpi->unscaled_last_source != NULL) {
-    if (cm->mi_cols * MI_SIZE != cpi->unscaled_last_source->y_width ||
-        cm->mi_rows * MI_SIZE != cpi->unscaled_last_source->y_height) {
-      scale_and_extend_frame_nonnormative(cpi->unscaled_last_source,
-                                          &cpi->scaled_last_source);
-      cpi->Last_Source = &cpi->scaled_last_source;
-    } else {
-      cpi->Last_Source = cpi->unscaled_last_source;
-    }
-  }
+  if (cpi->unscaled_last_source != NULL)
+    cpi->Last_Source = vp9_scale_if_required(cm, cpi->unscaled_last_source,
+                                             &cpi->scaled_last_source);
 
   vp9_scale_references(cpi);
 
@@ -2487,7 +2113,6 @@
 
   // Set various flags etc to special state if it is a key frame.
   if (frame_is_intra_only(cm)) {
-    setup_key_frame(cpi);
     // Reset the loop filter deltas and segmentation map.
     vp9_reset_segment_features(&cm->seg);
 
@@ -2527,7 +2152,7 @@
   // For 1 pass CBR, check if we are dropping this frame.
   // Never drop on key frame.
   if (cpi->pass == 0 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
+      cpi->oxcf.rc_mode == RC_MODE_CBR &&
       cm->frame_type != KEY_FRAME) {
     if (vp9_rc_drop_frame(cpi)) {
       vp9_rc_postencode_update_drop_frame(cpi);
@@ -2538,7 +2163,7 @@
 
   vp9_clear_system_state();
 
-  vp9_zero(cpi->rd_tx_select_threshes);
+  vp9_zero(cpi->rd.tx_select_threshes);
 
 #if CONFIG_VP9_POSTPROC
   if (cpi->oxcf.noise_sensitivity > 0) {
@@ -2647,22 +2272,23 @@
   output_frame_level_debug_stats(cpi);
 #endif
   if (cpi->refresh_golden_frame == 1)
-    cm->frame_flags |= FRAMEFLAGS_GOLDEN;
+    cpi->frame_flags |= FRAMEFLAGS_GOLDEN;
   else
-    cm->frame_flags &= ~FRAMEFLAGS_GOLDEN;
+    cpi->frame_flags &= ~FRAMEFLAGS_GOLDEN;
 
   if (cpi->refresh_alt_ref_frame == 1)
-    cm->frame_flags |= FRAMEFLAGS_ALTREF;
+    cpi->frame_flags |= FRAMEFLAGS_ALTREF;
   else
-    cm->frame_flags &= ~FRAMEFLAGS_ALTREF;
+    cpi->frame_flags &= ~FRAMEFLAGS_ALTREF;
 
   get_ref_frame_flags(cpi);
 
+  cm->last_frame_type = cm->frame_type;
   vp9_rc_postencode_update(cpi, *size);
 
   if (cm->frame_type == KEY_FRAME) {
     // Tell the caller that the frame was coded as a key frame
-    *frame_flags = cm->frame_flags | FRAMEFLAGS_KEY;
+    *frame_flags = cpi->frame_flags | FRAMEFLAGS_KEY;
 
 #if CONFIG_MULTIPLE_ARF
     // Reset the sequence number.
@@ -2673,7 +2299,7 @@
     }
 #endif
   } else {
-    *frame_flags = cm->frame_flags&~FRAMEFLAGS_KEY;
+    *frame_flags = cpi->frame_flags & ~FRAMEFLAGS_KEY;
 
 #if CONFIG_MULTIPLE_ARF
     /* Increment position in the coded frame sequence. */
@@ -2723,7 +2349,7 @@
 
 static void Pass0Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
                         unsigned int *frame_flags) {
-  if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+  if (cpi->oxcf.rc_mode == RC_MODE_CBR) {
     vp9_rc_get_one_pass_cbr_params(cpi);
   } else {
     vp9_rc_get_one_pass_vbr_params(cpi);
@@ -3014,7 +2640,7 @@
   }
 
   if (cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+      cpi->oxcf.rc_mode == RC_MODE_CBR) {
     vp9_update_temporal_layer_framerate(cpi);
     vp9_restore_layer_context(cpi);
   }
@@ -3042,7 +2668,16 @@
   }
 #endif
 
-  cm->frame_flags = *frame_flags;
+  cpi->frame_flags = *frame_flags;
+
+  if (cpi->pass == 2 &&
+      cm->current_video_frame == 0 &&
+      cpi->oxcf.allow_spatial_resampling &&
+      cpi->oxcf.rc_mode == RC_MODE_VBR) {
+    // Internal scaling is triggered on the first frame.
+    vp9_set_size_literal(cpi, cpi->oxcf.scaled_frame_width,
+                         cpi->oxcf.scaled_frame_height);
+  }
 
   // Reset the frame pointers to the current frame size
   vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
@@ -3097,7 +2732,7 @@
 
   // Save layer specific state.
   if ((cpi->svc.number_temporal_layers > 1 &&
-      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+      cpi->oxcf.rc_mode == RC_MODE_CBR) ||
       (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
     vp9_save_layer_context(cpi);
   }
@@ -3219,9 +2854,10 @@
                    unsigned int threshold[MAX_SEGMENTS]) {
   signed char feature_data[SEG_LVL_MAX][MAX_SEGMENTS];
   struct segmentation *seg = &cpi->common.seg;
+  const VP9_COMMON *const cm = &cpi->common;
   int i;
 
-  if (cpi->common.mb_rows != rows || cpi->common.mb_cols != cols)
+  if (cm->mb_rows != rows || cm->mb_cols != cols)
     return -1;
 
   if (!map) {
@@ -3229,8 +2865,7 @@
     return 0;
   }
 
-  // Set the segmentation Map
-  vp9_set_segmentation_map(cpi, map);
+  vpx_memcpy(cpi->segmentation_map, map, cm->mi_rows * cm->mi_cols);
 
   // Activate segmentation.
   vp9_enable_segmentation(seg);
diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_encoder.h
similarity index 89%
rename from vp9/encoder/vp9_onyx_int.h
rename to vp9/encoder/vp9_encoder.h
index 18203f9..364ea3a 100644
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef VP9_ENCODER_VP9_ONYX_INT_H_
-#define VP9_ENCODER_VP9_ONYX_INT_H_
+#ifndef VP9_ENCODER_VP9_ENCODER_H_
+#define VP9_ENCODER_VP9_ENCODER_H_
 
 #include <stdio.h>
 
@@ -132,43 +132,43 @@
 } VPX_SCALING;
 
 typedef enum {
-  USAGE_LOCAL_FILE_PLAYBACK = 0,
-  USAGE_STREAM_FROM_SERVER  = 1,
-  USAGE_CONSTRAINED_QUALITY = 2,
-  USAGE_CONSTANT_QUALITY    = 3,
-} END_USAGE;
+  RC_MODE_VBR = 0,
+  RC_MODE_CBR = 1,
+  RC_MODE_CONSTRAINED_QUALITY = 2,
+  RC_MODE_CONSTANT_QUALITY    = 3,
+} RC_MODE;
 
 typedef enum {
   // Good Quality Fast Encoding. The encoder balances quality with the
   // amount of time it takes to encode the output. (speed setting
   // controls how fast)
-  MODE_GOODQUALITY = 1,
+  ONE_PASS_GOOD = 1,
 
   // One Pass - Best Quality. The encoder places priority on the
   // quality of the output over encoding speed. The output is compressed
   // at the highest possible quality. This option takes the longest
   // amount of time to encode. (speed setting ignored)
-  MODE_BESTQUALITY = 2,
+  ONE_PASS_BEST = 2,
 
   // Two Pass - First Pass. The encoder generates a file of statistics
   // for use in the second encoding pass. (speed setting controls how fast)
-  MODE_FIRSTPASS = 3,
+  TWO_PASS_FIRST = 3,
 
   // Two Pass - Second Pass. The encoder uses the statistics that were
   // generated in the first encoding pass to create the compressed
   // output. (speed setting controls how fast)
-  MODE_SECONDPASS = 4,
+  TWO_PASS_SECOND_GOOD = 4,
 
   // Two Pass - Second Pass Best.  The encoder uses the statistics that
   // were generated in the first encoding pass to create the compressed
   // output using the highest possible quality, and taking a
   // longer amount of time to encode. (speed setting ignored)
-  MODE_SECONDPASS_BEST = 5,
+  TWO_PASS_SECOND_BEST = 5,
 
   // Realtime/Live Encoding. This mode is optimized for realtime
   // encoding (for example, capturing a television signal or feed from
   // a live camera). (speed setting controls how fast)
-  MODE_REALTIME = 6,
+  REALTIME = 6,
 } MODE;
 
 typedef enum {
@@ -185,7 +185,8 @@
   AQ_MODE_COUNT  // This should always be the last member of the enum
 } AQ_MODE;
 
-typedef struct VP9_CONFIG {
+
+typedef struct VP9EncoderConfig {
   BITSTREAM_PROFILE profile;
   BIT_DEPTH bit_depth;
   int width;  // width of data passed to the compressor
@@ -195,7 +196,7 @@
 
   int noise_sensitivity;  // pre processing blur: recommendation 0
   int sharpness;  // sharpening output: recommendation 0:
-  int cpu_used;
+  int speed;
   unsigned int rc_max_intra_bitrate_pct;
 
   MODE mode;
@@ -209,7 +210,7 @@
   // ----------------------------------------------------------------
   // DATARATE CONTROL OPTIONS
 
-  END_USAGE end_usage;  // vbr or cbr
+  RC_MODE rc_mode;  // vbr, cbr, constrained quality or constant quality
 
   // buffer targeting aggressiveness
   int under_shoot_pct;
@@ -231,6 +232,11 @@
   int lossless;
   AQ_MODE aq_mode;  // Adaptive Quantization mode
 
+  // Internal frame size scaling.
+  int allow_spatial_resampling;
+  int scaled_frame_width;
+  int scaled_frame_height;
+
   // Enable feature to reduce the frame quantization every x frames.
   int frame_periodic_boost;
 
@@ -279,13 +285,43 @@
   struct vpx_codec_pkt_list  *output_pkt_list;
 
   vp8e_tuning tuning;
-} VP9_CONFIG;
+} VP9EncoderConfig;
+
+static INLINE int is_best_mode(MODE mode) {
+  return mode == ONE_PASS_BEST || mode == TWO_PASS_SECOND_BEST;
+}
+
+typedef struct RD_OPT {
+  // Thresh_mult is used to set a threshold for the rd score. A higher value
+  // means that we will accept the best mode so far more often. This number
+  // is used in combination with the current block size, and thresh_freq_fact
+  // to pick a threshold.
+  int thresh_mult[MAX_MODES];
+  int thresh_mult_sub8x8[MAX_REFS];
+
+  int threshes[MAX_SEGMENTS][BLOCK_SIZES][MAX_MODES];
+  int thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
+
+  int64_t comp_pred_diff[REFERENCE_MODES];
+  int64_t prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
+  int64_t tx_select_diff[TX_MODES];
+  // FIXME(rbultje) can this overflow?
+  int tx_select_threshes[MAX_REF_FRAMES][TX_MODES];
+
+  int64_t filter_diff[SWITCHABLE_FILTER_CONTEXTS];
+  int64_t filter_threshes[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
+  int64_t filter_cache[SWITCHABLE_FILTER_CONTEXTS];
+  int64_t mask_filter;
+
+  int RDMULT;
+  int RDDIV;
+} RD_OPT;
 
 typedef struct VP9_COMP {
   QUANTS quants;
   MACROBLOCK mb;
   VP9_COMMON common;
-  VP9_CONFIG oxcf;
+  VP9EncoderConfig oxcf;
   struct lookahead_ctx    *lookahead;
   struct lookahead_entry  *source;
 #if CONFIG_MULTIPLE_ARF
@@ -302,8 +338,6 @@
   YV12_BUFFER_CONFIG *unscaled_last_source;
   YV12_BUFFER_CONFIG scaled_last_source;
 
-  int key_frame_frequency;
-
   int gold_is_last;  // gold same as last frame ( short circuit gold searches)
   int alt_is_last;  // Alt same as last ( short circuit altref search)
   int gold_is_alt;  // don't do both alt and gold search ( just do gold).
@@ -343,31 +377,7 @@
   // Ambient reconstruction err target for force key frames
   int ambient_err;
 
-  // Thresh_mult is used to set a threshold for the rd score. A higher value
-  // means that we will accept the best mode so far more often. This number
-  // is used in combination with the current block size, and thresh_freq_fact
-  // to pick a threshold.
-  int rd_thresh_mult[MAX_MODES];
-  int rd_thresh_mult_sub8x8[MAX_REFS];
-
-  int rd_threshes[MAX_SEGMENTS][BLOCK_SIZES][MAX_MODES];
-  int rd_thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
-  int rd_thresh_sub8x8[MAX_SEGMENTS][BLOCK_SIZES][MAX_REFS];
-  int rd_thresh_freq_sub8x8[BLOCK_SIZES][MAX_REFS];
-
-  int64_t rd_comp_pred_diff[REFERENCE_MODES];
-  int64_t rd_prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
-  int64_t rd_tx_select_diff[TX_MODES];
-  // FIXME(rbultje) can this overflow?
-  int rd_tx_select_threshes[MAX_REF_FRAMES][TX_MODES];
-
-  int64_t rd_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
-  int64_t rd_filter_threshes[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
-  int64_t rd_filter_cache[SWITCHABLE_FILTER_CONTEXTS];
-  int64_t mask_filter_rd;
-
-  int RDMULT;
-  int RDDIV;
+  RD_OPT rd;
 
   CODING_CONTEXT coding_context;
 
@@ -376,15 +386,12 @@
   int active_arnr_frames;           // <= cpi->oxcf.arnr_max_frames
   int active_arnr_strength;         // <= cpi->oxcf.arnr_max_strength
 
-  double output_framerate;
   int64_t last_time_stamp_seen;
   int64_t last_end_time_stamp_seen;
   int64_t first_time_stamp_ever;
 
   RATE_CONTROL rc;
 
-  int cq_target_quality;
-
   vp9_coeff_count coef_counts[TX_SIZES][PLANE_TYPES];
   vp9_coeff_probs_model frame_coef_probs[TX_SIZES][PLANE_TYPES];
 
@@ -394,10 +401,6 @@
   int mbgraph_n_frames;             // number of frames filled in the above
   int static_mb_pct;                // % forced skip mbs by segmentation
 
-  // for real time encoding
-  int speed;
-
-  int cpu_used;
   int pass;
 
   int ref_frame_flags;
@@ -441,7 +444,6 @@
 
   YV12_BUFFER_CONFIG alt_ref_buffer;
   YV12_BUFFER_CONFIG *frames[MAX_LAG_BUFFERS];
-  int fixed_divide[512];
 
 #if CONFIG_INTERNAL_STATS
   unsigned int mode_chosen_counts[MAX_MODES];
@@ -478,11 +480,6 @@
 #endif
   int b_calculate_psnr;
 
-  // Per MB activity measurement
-  unsigned int activity_avg;
-  unsigned int *mb_activity_map;
-  int *mb_norm_activity_map;
-
   int droppable;
 
   int dummy_packing;    /* flag to indicate if packing is dummy */
@@ -498,6 +495,10 @@
 
   int use_large_partition_rate;
 
+  int frame_flags;
+
+  search_site_config ss_cfg;
+
 #if CONFIG_MULTIPLE_ARF
   // ARF tracking variables.
   int multi_arf_enabled;
@@ -519,10 +520,10 @@
 
 void vp9_initialize_enc();
 
-struct VP9_COMP *vp9_create_compressor(VP9_CONFIG *oxcf);
+struct VP9_COMP *vp9_create_compressor(VP9EncoderConfig *oxcf);
 void vp9_remove_compressor(VP9_COMP *cpi);
 
-void vp9_change_config(VP9_COMP *cpi, const VP9_CONFIG *oxcf);
+void vp9_change_config(VP9_COMP *cpi, const VP9EncoderConfig *oxcf);
 
   // receive a frames worth of data. caller can assume that a copy of this
   // frame is made and not just a copy of the pointer..
@@ -591,9 +592,10 @@
 
 // Intra only frames, golden frames (except alt ref overlays) and
 // alt ref frames tend to be coded at a higher than ambient quality
-static INLINE int vp9_frame_is_boosted(const VP9_COMP *cpi) {
+static INLINE int frame_is_boosted(const VP9_COMP *cpi) {
   return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
-         (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
+         (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref) ||
+         vp9_is_upper_layer_key_frame(cpi);
 }
 
 static INLINE int get_token_alloc(int mb_rows, int mb_cols) {
@@ -616,6 +618,10 @@
 
 int64_t vp9_rescale(int64_t val, int64_t num, int denom);
 
+YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
+                                          YV12_BUFFER_CONFIG *unscaled,
+                                          YV12_BUFFER_CONFIG *scaled);
+
 static INLINE void set_ref_ptrs(VP9_COMMON *cm, MACROBLOCKD *xd,
                                 MV_REFERENCE_FRAME ref0,
                                 MV_REFERENCE_FRAME ref1) {
@@ -629,4 +635,4 @@
 }  // extern "C"
 #endif
 
-#endif  // VP9_ENCODER_VP9_ONYX_INT_H_
+#endif  // VP9_ENCODER_VP9_ENCODER_H_
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index db32ef8..5867fb3 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -28,10 +28,10 @@
 #include "vp9/encoder/vp9_encodeframe.h"
 #include "vp9/encoder/vp9_encodemb.h"
 #include "vp9/encoder/vp9_encodemv.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_extend.h"
 #include "vp9/encoder/vp9_firstpass.h"
 #include "vp9/encoder/vp9_mcomp.h"
-#include "vp9/encoder/vp9_onyx_int.h"
 #include "vp9/encoder/vp9_quantize.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 #include "vp9/encoder/vp9_rdopt.h"
@@ -61,7 +61,7 @@
 #define MIN_GF_INTERVAL             4
 #endif
 
-#define DISABLE_RC_LONG_TERM_MEM
+// #define LONG_TERM_VBR_CORRECTION
 
 static void swap_yv12(YV12_BUFFER_CONFIG *a, YV12_BUFFER_CONFIG *b) {
   YV12_BUFFER_CONFIG temp = *a;
@@ -336,8 +336,9 @@
 }
 
 // This function returns the maximum target rate per frame.
-static int frame_max_bits(const RATE_CONTROL *rc, const VP9_CONFIG *oxcf) {
-  int64_t max_bits = ((int64_t)rc->av_per_frame_bandwidth *
+static int frame_max_bits(const RATE_CONTROL *rc,
+                          const VP9EncoderConfig *oxcf) {
+  int64_t max_bits = ((int64_t)rc->avg_frame_bandwidth *
                           (int64_t)oxcf->two_pass_vbrmax_section) / 100;
   if (max_bits < 0)
     max_bits = 0;
@@ -376,37 +377,40 @@
   }
 }
 
-static unsigned int zz_motion_search(const MACROBLOCK *x) {
-  const MACROBLOCKD *const xd = &x->e_mbd;
-  const uint8_t *const src = x->plane[0].src.buf;
-  const int src_stride = x->plane[0].src.stride;
-  const uint8_t *const ref = xd->plane[0].pre[0].buf;
-  const int ref_stride = xd->plane[0].pre[0].stride;
+static unsigned int get_prediction_error(BLOCK_SIZE bsize,
+                                         const struct buf_2d *src,
+                                         const struct buf_2d *ref) {
   unsigned int sse;
-  vp9_variance_fn_t fn = get_block_variance_fn(xd->mi[0]->mbmi.sb_type);
-  fn(src, src_stride, ref, ref_stride, &sse);
+  const vp9_variance_fn_t fn = get_block_variance_fn(bsize);
+  fn(src->buf, src->stride, ref->buf, ref->stride, &sse);
   return sse;
 }
 
+// Refine the motion search range according to the frame dimension
+// for first pass test.
+static int get_search_range(const VP9_COMMON *cm) {
+  int sr = 0;
+  const int dim = MIN(cm->width, cm->height);
+
+  while ((dim << sr) < MAX_FULL_PEL_VAL)
+    ++sr;
+  return sr;
+}
+
 static void first_pass_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
                                      const MV *ref_mv, MV *best_mv,
                                      int *best_motion_err) {
   MACROBLOCKD *const xd = &x->e_mbd;
   MV tmp_mv = {0, 0};
   MV ref_mv_full = {ref_mv->row >> 3, ref_mv->col >> 3};
-  int num00, tmp_err, n, sr = 0;
-  int step_param = 3;
-  int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param;
+  int num00, tmp_err, n;
   const BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
   vp9_variance_fn_ptr_t v_fn_ptr = cpi->fn_ptr[bsize];
-  int new_mv_mode_penalty = 256;
-  const int quart_frm = MIN(cpi->common.width, cpi->common.height);
+  const int new_mv_mode_penalty = 256;
 
-  // Refine the motion search range according to the frame dimension
-  // for first pass test.
-  while ((quart_frm << sr) < MAX_FULL_PEL_VAL)
-    ++sr;
-
+  int step_param = 3;
+  int further_steps = (MAX_MVSEARCH_STEPS - 1) - step_param;
+  const int sr = get_search_range(&cpi->common);
   step_param += sr;
   further_steps -= sr;
 
@@ -414,11 +418,9 @@
   v_fn_ptr.vf = get_block_variance_fn(bsize);
 
   // Center the initial step/diamond search on best mv.
-  tmp_err = cpi->diamond_search_sad(x, &ref_mv_full, &tmp_mv,
+  tmp_err = cpi->diamond_search_sad(x, &cpi->ss_cfg, &ref_mv_full, &tmp_mv,
                                     step_param,
-                                    x->sadperbit16, &num00, &v_fn_ptr,
-                                    x->nmvjointcost,
-                                    x->mvcost, ref_mv);
+                                    x->sadperbit16, &num00, &v_fn_ptr, ref_mv);
   if (tmp_err < INT_MAX)
     tmp_err = vp9_get_mvpred_var(x, &tmp_mv, ref_mv, &v_fn_ptr, 1);
   if (tmp_err < INT_MAX - new_mv_mode_penalty)
@@ -426,8 +428,7 @@
 
   if (tmp_err < *best_motion_err) {
     *best_motion_err = tmp_err;
-    best_mv->row = tmp_mv.row;
-    best_mv->col = tmp_mv.col;
+    *best_mv = tmp_mv;
   }
 
   // Carry out further step/diamond searches as necessary.
@@ -440,11 +441,9 @@
     if (num00) {
       --num00;
     } else {
-      tmp_err = cpi->diamond_search_sad(x, &ref_mv_full, &tmp_mv,
+      tmp_err = cpi->diamond_search_sad(x, &cpi->ss_cfg, &ref_mv_full, &tmp_mv,
                                         step_param + n, x->sadperbit16,
-                                        &num00, &v_fn_ptr,
-                                        x->nmvjointcost,
-                                        x->mvcost, ref_mv);
+                                        &num00, &v_fn_ptr, ref_mv);
       if (tmp_err < INT_MAX)
         tmp_err = vp9_get_mvpred_var(x, &tmp_mv, ref_mv, &v_fn_ptr, 1);
       if (tmp_err < INT_MAX - new_mv_mode_penalty)
@@ -452,8 +451,7 @@
 
       if (tmp_err < *best_motion_err) {
         *best_motion_err = tmp_err;
-        best_mv->row = tmp_mv.row;
-        best_mv->col = tmp_mv.col;
+        *best_mv = tmp_mv;
       }
     }
   }
@@ -477,7 +475,7 @@
   TileInfo tile;
   struct macroblock_plane *const p = x->plane;
   struct macroblockd_plane *const pd = xd->plane;
-  const PICK_MODE_CONTEXT *ctx = &x->sb64_context;
+  const PICK_MODE_CONTEXT *ctx = &x->pc_root->none;
   int i;
 
   int recon_yoffset, recon_uvoffset;
@@ -535,6 +533,9 @@
     // Disable golden frame for svc first pass for now.
     gld_yv12 = NULL;
     set_ref_ptrs(cm, xd, ref_frame, NONE);
+
+    cpi->Source = vp9_scale_if_required(cm, cpi->un_scaled_source,
+                                        &cpi->scaled_source);
   }
 
   vp9_setup_src_planes(x, cpi->Source, 0, 0);
@@ -603,7 +604,13 @@
       }
 
       // Do intra 16x16 prediction.
-      this_error = vp9_encode_intra(x, use_dc_pred);
+      x->skip_encode = 0;
+      xd->mi[0]->mbmi.mode = DC_PRED;
+      xd->mi[0]->mbmi.tx_size = use_dc_pred ?
+         (bsize >= BLOCK_16X16 ? TX_16X16 : TX_8X8) : TX_4X4;
+      vp9_encode_intra_block_plane(x, bsize, 0);
+      this_error = vp9_get_mb_ss(x->plane[0].src_diff);
+
       if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
         vp9_clear_system_state();
         this_error = (int)(this_error * error_weight);
@@ -632,7 +639,8 @@
         int_mv mv, tmp_mv;
 
         xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset;
-        motion_error = zz_motion_search(x);
+        motion_error = get_prediction_error(bsize, &x->plane[0].src,
+                                            &xd->plane[0].pre[0]);
         // Assume 0,0 motion with no mv overhead.
         mv.as_int = tmp_mv.as_int = 0;
 
@@ -668,7 +676,8 @@
           int gf_motion_error;
 
           xd->plane[0].pre[0].buf = gld_yv12->y_buffer + recon_yoffset;
-          gf_motion_error = zz_motion_search(x);
+          gf_motion_error = get_prediction_error(bsize, &x->plane[0].src,
+                                                 &xd->plane[0].pre[0]);
 
           first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv.as_mv,
                                    &gf_motion_error);
@@ -849,6 +858,8 @@
     ++twopass->sr_update_lag;
   }
 
+  vp9_extend_frame_borders(new_yv12);
+
   if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
     vp9_update_reference_frames(cpi);
   } else {
@@ -856,8 +867,6 @@
     swap_yv12(lst_yv12, new_yv12);
   }
 
-  vp9_extend_frame_borders(lst_yv12);
-
   // Special case for the first frame. Copy into the GF buffer as a second
   // reference.
   if (cm->current_video_frame == 0 && gld_yv12 != NULL) {
@@ -901,56 +910,59 @@
   return fclamp(pow(error_term, power_term), 0.05, 5.0);
 }
 
-int vp9_twopass_worst_quality(VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
-                              int section_target_bandwitdh) {
-  int q;
-  const int num_mbs = cpi->common.MBs;
-  int target_norm_bits_per_mb;
+static int get_twopass_worst_quality(const VP9_COMP *cpi,
+                                     const FIRSTPASS_STATS *stats,
+                                     int section_target_bandwidth) {
   const RATE_CONTROL *const rc = &cpi->rc;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
 
-  const double section_err = fpstats->coded_error / fpstats->count;
-  const double err_per_mb = section_err / num_mbs;
-  const double speed_term = 1.0 + ((double)cpi->speed * 0.04);
+  if (section_target_bandwidth <= 0) {
+    return rc->worst_quality;  // Highest value allowed
+  } else {
+    const int num_mbs = cpi->common.MBs;
+    const double section_err = stats->coded_error / stats->count;
+    const double err_per_mb = section_err / num_mbs;
+    const double speed_term = 1.0 + 0.04 * oxcf->speed;
+    const int target_norm_bits_per_mb = ((uint64_t)section_target_bandwidth <<
+                                            BPER_MB_NORMBITS) / num_mbs;
+    int q;
+    int is_svc_upper_layer = 0;
+    if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
+        cpi->svc.spatial_layer_id > 0) {
+      is_svc_upper_layer = 1;
+    }
 
-  if (section_target_bandwitdh <= 0)
-    return rc->worst_quality;          // Highest value allowed
+    // Try and pick a max Q that will be high enough to encode the
+    // content at the given rate.
+    for (q = rc->best_quality; q < rc->worst_quality; ++q) {
+      const double factor =
+          calc_correction_factor(err_per_mb, ERR_DIVISOR,
+                                 is_svc_upper_layer ? 0.8 : 0.5,
+                                 is_svc_upper_layer ? 1.0 : 0.90, q);
+      const int bits_per_mb = vp9_rc_bits_per_mb(INTER_FRAME, q,
+                                                 factor * speed_term);
+      if (bits_per_mb <= target_norm_bits_per_mb)
+        break;
+    }
 
-  target_norm_bits_per_mb =
-      ((uint64_t)section_target_bandwitdh << BPER_MB_NORMBITS) / num_mbs;
-
-  // Try and pick a max Q that will be high enough to encode the
-  // content at the given rate.
-  for (q = rc->best_quality; q < rc->worst_quality; ++q) {
-    const double err_correction_factor = calc_correction_factor(err_per_mb,
-                                             ERR_DIVISOR, 0.5, 0.90, q);
-    const int bits_per_mb_at_this_q =
-      vp9_rc_bits_per_mb(INTER_FRAME, q, (err_correction_factor * speed_term));
-    if (bits_per_mb_at_this_q <= target_norm_bits_per_mb)
-      break;
+    // Restriction on active max q for constrained quality mode.
+    if (cpi->oxcf.rc_mode == RC_MODE_CONSTRAINED_QUALITY)
+      q = MAX(q, oxcf->cq_level);
+    return q;
   }
-
-  // Restriction on active max q for constrained quality mode.
-  if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY)
-    q = MAX(q, cpi->cq_target_quality);
-
-  return q;
 }
 
 extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
 
 void vp9_init_second_pass(VP9_COMP *cpi) {
   SVC *const svc = &cpi->svc;
-  FIRSTPASS_STATS this_frame;
-  const FIRSTPASS_STATS *start_pos;
-  struct twopass_rc *twopass = &cpi->twopass;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   const int is_spatial_svc = (svc->number_spatial_layers > 1) &&
                              (svc->number_temporal_layers == 1);
+  struct twopass_rc *const twopass = is_spatial_svc ?
+      &svc->layer_context[svc->spatial_layer_id].twopass : &cpi->twopass;
   double frame_rate;
-
-  if (is_spatial_svc) {
-    twopass = &svc->layer_context[svc->spatial_layer_id].twopass;
-  }
+  FIRSTPASS_STATS *stats;
 
   zero_stats(&twopass->total_stats);
   zero_stats(&twopass->total_left_stats);
@@ -958,11 +970,12 @@
   if (!twopass->stats_in_end)
     return;
 
-  twopass->total_stats = *twopass->stats_in_end;
-  twopass->total_left_stats = twopass->total_stats;
+  stats = &twopass->total_stats;
 
-  frame_rate = 10000000.0 * twopass->total_stats.count /
-               twopass->total_stats.duration;
+  *stats = *twopass->stats_in_end;
+  twopass->total_left_stats = *stats;
+
+  frame_rate = 10000000.0 * stats->count / stats->duration;
   // Each frame can have a different duration, as the frame rate in the source
   // isn't guaranteed to be constant. The frame rate prior to the first frame
   // encoded in the second pass is a guess. However, the sum duration is not.
@@ -971,18 +984,15 @@
 
   if (is_spatial_svc) {
     vp9_update_spatial_layer_framerate(cpi, frame_rate);
-    twopass->bits_left =
-        (int64_t)(twopass->total_stats.duration *
+    twopass->bits_left = (int64_t)(stats->duration *
         svc->layer_context[svc->spatial_layer_id].target_bandwidth /
         10000000.0);
   } else {
     vp9_new_framerate(cpi, frame_rate);
-    twopass->bits_left = (int64_t)(twopass->total_stats.duration *
-                                   oxcf->target_bandwidth / 10000000.0);
+    twopass->bits_left = (int64_t)(stats->duration * oxcf->target_bandwidth /
+                             10000000.0);
   }
 
-  cpi->output_framerate = oxcf->framerate;
-
   // Calculate a minimum intra value to be used in determining the IIratio
   // scores used in the second pass. We have this minimum to make sure
   // that clips that are static but "low complexity" in the intra domain
@@ -1000,8 +1010,9 @@
   // Scan the first pass file and calculate an average Intra / Inter error
   // score ratio for the sequence.
   {
+    const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+    FIRSTPASS_STATS this_frame;
     double sum_iiratio = 0.0;
-    start_pos = twopass->stats_in;
 
     while (input_stats(twopass, &this_frame) != EOF) {
       const double iiratio = this_frame.intra_error /
@@ -1010,7 +1021,7 @@
     }
 
     twopass->avg_iiratio = sum_iiratio /
-        DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
+                               DOUBLE_DIVIDE_CHECK((double)stats->count);
 
     reset_fpf_position(twopass, start_pos);
   }
@@ -1018,16 +1029,17 @@
   // Scan the first pass file and calculate a modified total error based upon
   // the bias/power function used to allocate bits.
   {
-    double av_error = twopass->total_stats.ssim_weighted_pred_err /
-                      DOUBLE_DIVIDE_CHECK(twopass->total_stats.count);
+    const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+    FIRSTPASS_STATS this_frame;
+    const double av_error = stats->ssim_weighted_pred_err /
+                                DOUBLE_DIVIDE_CHECK(stats->count);
 
-    start_pos = twopass->stats_in;
 
     twopass->modified_error_total = 0.0;
     twopass->modified_error_min =
-      (av_error * oxcf->two_pass_vbrmin_section) / 100;
+        (av_error * oxcf->two_pass_vbrmin_section) / 100;
     twopass->modified_error_max =
-      (av_error * oxcf->two_pass_vbrmax_section) / 100;
+        (av_error * oxcf->two_pass_vbrmax_section) / 100;
 
     while (input_stats(twopass, &this_frame) != EOF) {
       twopass->modified_error_total +=
@@ -1037,6 +1049,9 @@
 
     reset_fpf_position(twopass, start_pos);
   }
+
+  // Reset the vbr bits off target counter
+  cpi->rc.vbr_bits_off_target = 0;
 }
 
 // This function gives an estimate of how badly we believe the prediction
@@ -1405,7 +1420,7 @@
 // Analyse and define a gf/arf group.
 static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
   RATE_CONTROL *const rc = &cpi->rc;
-  VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   struct twopass_rc *const twopass = &cpi->twopass;
   FIRSTPASS_STATS next_frame = { 0 };
   const FIRSTPASS_STATS *start_pos;
@@ -1725,8 +1740,8 @@
       twopass->gf_bits = gf_bits;
     }
     if (i == 1 ||
-        (!rc->source_alt_ref_pending &&
-         cpi->common.frame_type != KEY_FRAME)) {
+        (!rc->source_alt_ref_pending && cpi->common.frame_type != KEY_FRAME &&
+         !vp9_is_upper_layer_key_frame(cpi))) {
       // Calculate the per frame bit target for this frame.
       vp9_rc_set_frame_target(cpi, gf_bits);
     }
@@ -1933,7 +1948,8 @@
 
   // Find the next keyframe.
   i = 0;
-  while (twopass->stats_in < twopass->stats_in_end) {
+  while (twopass->stats_in < twopass->stats_in_end &&
+         rc->frames_to_key < cpi->oxcf.key_freq) {
     // Accumulate kf group error.
     kf_group_err += calculate_modified_err(cpi, this_frame);
 
@@ -1963,7 +1979,7 @@
 
       // Special check for transition or high motion followed by a
       // static scene.
-      if (detect_transition_to_still(twopass, i, cpi->key_frame_frequency - i,
+      if (detect_transition_to_still(twopass, i, cpi->oxcf.key_freq - i,
                                      loop_decay_rate, decay_accumulator))
         break;
 
@@ -1971,8 +1987,8 @@
       ++rc->frames_to_key;
 
       // If we don't have a real key frame within the next two
-      // key_frame_frequency intervals then break out of the loop.
-      if (rc->frames_to_key >= 2 * (int)cpi->key_frame_frequency)
+      // key_freq intervals then break out of the loop.
+      if (rc->frames_to_key >= 2 * cpi->oxcf.key_freq)
         break;
     } else {
       ++rc->frames_to_key;
@@ -1985,7 +2001,7 @@
   // This code centers the extra kf if the actual natural interval
   // is between 1x and 2x.
   if (cpi->oxcf.auto_key &&
-      rc->frames_to_key > (int)cpi->key_frame_frequency) {
+      rc->frames_to_key > cpi->oxcf.key_freq) {
     FIRSTPASS_STATS tmp_frame = first_frame;
 
     rc->frames_to_key /= 2;
@@ -2001,7 +2017,8 @@
       input_stats(twopass, &tmp_frame);
     }
     rc->next_key_frame_forced = 1;
-  } else if (twopass->stats_in == twopass->stats_in_end) {
+  } else if (twopass->stats_in == twopass->stats_in_end ||
+             rc->frames_to_key >= cpi->oxcf.key_freq) {
     rc->next_key_frame_forced = 1;
   } else {
     rc->next_key_frame_forced = 0;
@@ -2187,7 +2204,7 @@
   VP9_COMMON *const cm = &cpi->common;
   if (!cpi->refresh_alt_ref_frame &&
       (cm->current_video_frame == 0 ||
-       (cm->frame_flags & FRAMEFLAGS_KEY))) {
+       (cpi->frame_flags & FRAMEFLAGS_KEY))) {
     cm->frame_type = KEY_FRAME;
   } else {
     cm->frame_type = INTER_FRAME;
@@ -2196,6 +2213,23 @@
   cpi->rc.frames_to_key = INT_MAX;
 }
 
+// For VBR...adjustment to the frame target based on error from previous frames
+void vbr_rate_correction(int * this_frame_target,
+                         const int64_t vbr_bits_off_target) {
+  int max_delta = (*this_frame_target * 15) / 100;
+
+  // vbr_bits_off_target > 0 means we have extra bits to spend
+  if (vbr_bits_off_target > 0) {
+    *this_frame_target +=
+      (vbr_bits_off_target > max_delta) ? max_delta
+                                        : (int)vbr_bits_off_target;
+  } else {
+    *this_frame_target -=
+      (vbr_bits_off_target < -max_delta) ? max_delta
+                                         : (int)-vbr_bits_off_target;
+  }
+}
+
 void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
@@ -2223,8 +2257,15 @@
     return;
 
   if (cpi->refresh_alt_ref_frame) {
+    int modified_target = twopass->gf_bits;
+    rc->base_frame_target = twopass->gf_bits;
     cm->frame_type = INTER_FRAME;
-    vp9_rc_set_frame_target(cpi, twopass->gf_bits);
+#ifdef LONG_TERM_VBR_CORRECTION
+    // Correction to rate target based on prior over or under shoot.
+    if (cpi->oxcf.rc_mode == RC_MODE_VBR)
+      vbr_rate_correction(&modified_target, rc->vbr_bits_off_target);
+#endif
+    vp9_rc_set_frame_target(cpi, modified_target);
     return;
   }
 
@@ -2235,14 +2276,14 @@
     twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
   }
 
-  if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
+  if (cpi->oxcf.rc_mode == RC_MODE_CONSTANT_QUALITY) {
     twopass->active_worst_quality = cpi->oxcf.cq_level;
   } else if (cm->current_video_frame == 0 ||
              (is_spatial_svc && lc->current_video_frame_in_layer == 0)) {
     // Special case code for first frame.
     const int section_target_bandwidth = (int)(twopass->bits_left /
                                                frames_left);
-    const int tmp_q = vp9_twopass_worst_quality(cpi, &twopass->total_left_stats,
+    const int tmp_q = get_twopass_worst_quality(cpi, &twopass->total_left_stats,
                                                 section_target_bandwidth);
     twopass->active_worst_quality = tmp_q;
     rc->ni_av_qi = tmp_q;
@@ -2257,16 +2298,21 @@
 
   // Keyframe and section processing.
   if (rc->frames_to_key == 0 ||
-      (cm->frame_flags & FRAMEFLAGS_KEY)) {
+      (cpi->frame_flags & FRAMEFLAGS_KEY)) {
     // Define next KF group and assign bits to it.
     this_frame_copy = this_frame;
     find_next_key_frame(cpi, &this_frame_copy);
     // Don't place key frame in any enhancement layers in spatial svc
-    if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
-        cpi->svc.spatial_layer_id > 0) {
-      cm->frame_type = INTER_FRAME;
+    if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+      lc->is_key_frame = 1;
+      if (cpi->svc.spatial_layer_id > 0) {
+        cm->frame_type = INTER_FRAME;
+      }
     }
   } else {
+    if (cpi->use_svc && cpi->svc.number_temporal_layers == 1) {
+      lc->is_key_frame = 0;
+    }
     cm->frame_type = INTER_FRAME;
   }
 
@@ -2319,6 +2365,13 @@
     target = vp9_rc_clamp_iframe_target_size(cpi, rc->this_frame_target);
   else
     target = vp9_rc_clamp_pframe_target_size(cpi, rc->this_frame_target);
+
+  rc->base_frame_target = target;
+#ifdef LONG_TERM_VBR_CORRECTION
+  // Correction to rate target based on prior over or under shoot.
+  if (cpi->oxcf.rc_mode == RC_MODE_VBR)
+    vbr_rate_correction(&target, rc->vbr_bits_off_target);
+#endif
   vp9_rc_set_frame_target(cpi, target);
 
   // Update the total stats remaining structure.
@@ -2326,20 +2379,47 @@
 }
 
 void vp9_twopass_postencode_update(VP9_COMP *cpi) {
-#ifdef DISABLE_RC_LONG_TERM_MEM
-  const uint64_t bits_used = cpi->rc.this_frame_target;
+  RATE_CONTROL *const rc = &cpi->rc;
+#ifdef LONG_TERM_VBR_CORRECTION
+  // In this experimental mode, the VBR correction is done exclusively through
+  // rc->vbr_bits_off_target. Based on the sign of this value, a limited %
+  // adjustment is made to the target rate of subsequent frames, to try and
+  // push it back towards 0. This mode is less likely to suffer from
+  // extreme behaviour at the end of a clip or group of frames.
+  const int bits_used = rc->base_frame_target;
+  rc->vbr_bits_off_target += rc->base_frame_target - rc->projected_frame_size;
 #else
-  const uint64_t bits_used = cpi->rc.projected_frame_size;
+  // In this mode, VBR correction is acheived by altering bits_left,
+  // kf_group_bits & gf_group_bits to reflect any deviation from the target
+  // rate in this frame. This alters the allocation of bits to the
+  // remaning frames in the group / clip.
+  //
+  // This method can give rise to unstable behaviour near the end of a clip
+  // or kf/gf group of frames where any accumulated error is corrected over an
+  // ever decreasing number of frames. Hence we change the balance of target
+  // vs. actual bitrate gradually as we progress towards the end of the
+  // sequence in order to mitigate this effect.
+  const double progress =
+      (double)(cpi->twopass.stats_in - cpi->twopass.stats_in_start) /
+              (cpi->twopass.stats_in_end - cpi->twopass.stats_in_start);
+  const int bits_used = progress * rc->this_frame_target +
+                        (1.0 - progress) * rc->projected_frame_size;
 #endif
+
   cpi->twopass.bits_left -= bits_used;
   cpi->twopass.bits_left = MAX(cpi->twopass.bits_left, 0);
-  // Update bits left to the kf and gf groups to account for overshoot or
-  // undershoot on these frames.
-  if (cpi->common.frame_type == KEY_FRAME) {
+
+#ifdef LONG_TERM_VBR_CORRECTION
+  if (cpi->common.frame_type != KEY_FRAME &&
+      !vp9_is_upper_layer_key_frame(cpi)) {
+#else
+  if (cpi->common.frame_type == KEY_FRAME ||
+      vp9_is_upper_layer_key_frame(cpi)) {
     // For key frames kf_group_bits already had the target bits subtracted out.
     // So now update to the correct value based on the actual bits used.
     cpi->twopass.kf_group_bits += cpi->rc.this_frame_target - bits_used;
   } else {
+#endif
     cpi->twopass.kf_group_bits -= bits_used;
     cpi->twopass.gf_group_bits -= bits_used;
     cpi->twopass.gf_group_bits = MAX(cpi->twopass.gf_group_bits, 0);
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index 7a16c8f..f7ba423 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -91,8 +91,6 @@
 
 void vp9_init_second_pass(struct VP9_COMP *cpi);
 void vp9_rc_get_second_pass_params(struct VP9_COMP *cpi);
-int vp9_twopass_worst_quality(struct VP9_COMP *cpi, FIRSTPASS_STATS *fpstats,
-                              int section_target_bandwitdh);
 
 // Post encode update of the rate control parameters for 2-pass
 void vp9_twopass_postencode_update(struct VP9_COMP *cpi);
diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c
index cf03e01..abe71e6 100644
--- a/vp9/encoder/vp9_lookahead.c
+++ b/vp9/encoder/vp9_lookahead.c
@@ -14,9 +14,12 @@
 
 #include "vp9/common/vp9_common.h"
 
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_extend.h"
 #include "vp9/encoder/vp9_lookahead.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+
+// The max of past frames we want to keep in the queue.
+#define MAX_PRE_FRAMES 1
 
 struct lookahead_ctx {
   unsigned int max_sz;         /* Absolute size of the queue */
diff --git a/vp9/encoder/vp9_lookahead.h b/vp9/encoder/vp9_lookahead.h
index 046c533..ff63c0d 100644
--- a/vp9/encoder/vp9_lookahead.h
+++ b/vp9/encoder/vp9_lookahead.h
@@ -20,9 +20,6 @@
 
 #define MAX_LAG_BUFFERS 25
 
-// The max of past frames we want to keep in the queue.
-#define MAX_PRE_FRAMES 1
-
 struct lookahead_entry {
   YV12_BUFFER_CONFIG  img;
   int64_t             ts_start;
diff --git a/vp9/encoder/vp9_mbgraph.c b/vp9/encoder/vp9_mbgraph.c
index 44b171f..e7dcc7a 100644
--- a/vp9/encoder/vp9_mbgraph.c
+++ b/vp9/encoder/vp9_mbgraph.c
@@ -38,8 +38,8 @@
 
   // Further step/diamond searches as necessary
   int step_param = cpi->sf.reduce_first_step_size +
-      (cpi->speed < 8 ? (cpi->speed > 5 ? 1 : 0) : 2);
-  step_param = MIN(step_param, (cpi->sf.max_step_search_steps - 2));
+                       (cpi->oxcf.speed > 5 ? 1 : 0);
+  step_param = MIN(step_param, cpi->sf.max_step_search_steps - 2);
 
   vp9_set_mv_search_range(x, ref_mv);
 
@@ -77,12 +77,12 @@
           INT_MAX);
 }
 
-static int do_16x16_motion_search(VP9_COMP *cpi, const int_mv *ref_mv,
+static int do_16x16_motion_search(VP9_COMP *cpi, const MV *ref_mv,
                                   int_mv *dst_mv, int mb_row, int mb_col) {
   MACROBLOCK *const x = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
   unsigned int err, tmp_err;
-  int_mv tmp_mv;
+  MV tmp_mv;
 
   // Try zero MV first
   // FIXME should really use something like near/nearest MV and/or MV prediction
@@ -93,24 +93,22 @@
 
   // Test last reference frame using the previous best mv as the
   // starting point (best reference) for the search
-  tmp_err = do_16x16_motion_iteration(cpi, &ref_mv->as_mv, &tmp_mv.as_mv,
-                                      mb_row, mb_col);
+  tmp_err = do_16x16_motion_iteration(cpi, ref_mv, &tmp_mv, mb_row, mb_col);
   if (tmp_err < err) {
     err = tmp_err;
-    dst_mv->as_int = tmp_mv.as_int;
+    dst_mv->as_mv = tmp_mv;
   }
 
   // If the current best reference mv is not centered on 0,0 then do a 0,0
   // based search as well.
-  if (ref_mv->as_int) {
+  if (ref_mv->row != 0 || ref_mv->col != 0) {
     unsigned int tmp_err;
-    int_mv zero_ref_mv, tmp_mv;
+    MV zero_ref_mv = {0, 0}, tmp_mv;
 
-    zero_ref_mv.as_int = 0;
-    tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv.as_mv, &tmp_mv.as_mv,
+    tmp_err = do_16x16_motion_iteration(cpi, &zero_ref_mv, &tmp_mv,
                                         mb_row, mb_col);
     if (tmp_err < err) {
-      dst_mv->as_int = tmp_mv.as_int;
+      dst_mv->as_mv = tmp_mv;
       err = tmp_err;
     }
   }
@@ -133,11 +131,10 @@
 
   return err;
 }
-static int find_best_16x16_intra(VP9_COMP *cpi,
-                                 MB_PREDICTION_MODE *pbest_mode) {
+static int find_best_16x16_intra(VP9_COMP *cpi, PREDICTION_MODE *pbest_mode) {
   MACROBLOCK   *const x  = &cpi->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
-  MB_PREDICTION_MODE best_mode = -1, mode;
+  PREDICTION_MODE best_mode = -1, mode;
   unsigned int best_err = INT_MAX;
 
   // calculate SATD for each intra prediction mode;
@@ -173,7 +170,7 @@
   YV12_BUFFER_CONFIG *buf,
   int mb_y_offset,
   YV12_BUFFER_CONFIG *golden_ref,
-  int_mv *prev_golden_ref_mv,
+  const MV *prev_golden_ref_mv,
   YV12_BUFFER_CONFIG *alt_ref,
   int mb_row,
   int mb_col
@@ -239,13 +236,11 @@
 
   int mb_col, mb_row, offset = 0;
   int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
-  int_mv arf_top_mv, gld_top_mv;
+  MV arf_top_mv = {0, 0}, gld_top_mv = {0, 0};
   MODE_INFO mi_local = { { 0 } };
 
   // Set up limit values for motion vectors to prevent them extending outside
   // the UMV borders.
-  arf_top_mv.as_int = 0;
-  gld_top_mv.as_int = 0;
   x->mv_row_min     = -BORDER_MV_PIXELS_B16;
   x->mv_row_max     = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
   xd->up_available  = 0;
@@ -258,15 +253,13 @@
   mi_local.mbmi.ref_frame[1] = NONE;
 
   for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
-    int_mv arf_left_mv, gld_left_mv;
+    MV arf_left_mv = arf_top_mv, gld_left_mv = gld_top_mv;
     int mb_y_in_offset  = mb_y_offset;
     int arf_y_in_offset = arf_y_offset;
     int gld_y_in_offset = gld_y_offset;
 
     // Set up limit values for motion vectors to prevent them extending outside
     // the UMV borders.
-    arf_left_mv.as_int = arf_top_mv.as_int;
-    gld_left_mv.as_int = gld_top_mv.as_int;
     x->mv_col_min      = -BORDER_MV_PIXELS_B16;
     x->mv_col_max      = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
     xd->left_available = 0;
@@ -277,11 +270,11 @@
       update_mbgraph_mb_stats(cpi, mb_stats, buf, mb_y_in_offset,
                               golden_ref, &gld_left_mv, alt_ref,
                               mb_row, mb_col);
-      arf_left_mv.as_int = mb_stats->ref[ALTREF_FRAME].m.mv.as_int;
-      gld_left_mv.as_int = mb_stats->ref[GOLDEN_FRAME].m.mv.as_int;
+      arf_left_mv = mb_stats->ref[ALTREF_FRAME].m.mv.as_mv;
+      gld_left_mv = mb_stats->ref[GOLDEN_FRAME].m.mv.as_mv;
       if (mb_col == 0) {
-        arf_top_mv.as_int = arf_left_mv.as_int;
-        gld_top_mv.as_int = gld_left_mv.as_int;
+        arf_top_mv = arf_left_mv;
+        gld_top_mv = gld_left_mv;
       }
       xd->left_available = 1;
       mb_y_in_offset    += 16;
diff --git a/vp9/encoder/vp9_mbgraph.h b/vp9/encoder/vp9_mbgraph.h
index bc2a704..c3af972 100644
--- a/vp9/encoder/vp9_mbgraph.h
+++ b/vp9/encoder/vp9_mbgraph.h
@@ -20,7 +20,7 @@
     int err;
     union {
       int_mv mv;
-      MB_PREDICTION_MODE mode;
+      PREDICTION_MODE mode;
     } m;
   } ref[MAX_REF_FRAMES];
 } MBGRAPH_MB_STATS;
diff --git a/vp9/encoder/vp9_mcomp.c b/vp9/encoder/vp9_mcomp.c
index f7a02a4..bbec4da 100644
--- a/vp9/encoder/vp9_mcomp.c
+++ b/vp9/encoder/vp9_mcomp.c
@@ -18,7 +18,7 @@
 
 #include "vp9/common/vp9_common.h"
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_mcomp.h"
 
 // #define NEW_DIAMOND_SEARCH
@@ -66,7 +66,7 @@
 }
 
 static INLINE int mv_cost(const MV *mv,
-                          const int *joint_cost, int *comp_cost[2]) {
+                          const int *joint_cost, int *const comp_cost[2]) {
   return joint_cost[vp9_get_mv_joint(mv)] +
              comp_cost[0][mv->row] + comp_cost[1][mv->col];
 }
@@ -90,44 +90,43 @@
   return 0;
 }
 
-static int mvsad_err_cost(const MV *mv, const MV *ref,
-                          const int *mvjsadcost, int *mvsadcost[2],
+static int mvsad_err_cost(const MACROBLOCK *x, const MV *mv, const MV *ref,
                           int error_per_bit) {
-  if (mvsadcost) {
+  if (x->nmvsadcost) {
     const MV diff = { mv->row - ref->row,
                       mv->col - ref->col };
-    return ROUND_POWER_OF_TWO(mv_cost(&diff, mvjsadcost, mvsadcost) *
-                                  error_per_bit, 8);
+    return ROUND_POWER_OF_TWO(mv_cost(&diff, x->nmvjointsadcost,
+                                      x->nmvsadcost) * error_per_bit, 8);
   }
   return 0;
 }
 
-void vp9_init_dsmotion_compensation(MACROBLOCK *x, int stride) {
+void vp9_init_dsmotion_compensation(search_site_config *cfg, int stride) {
   int len, ss_count = 1;
 
-  x->ss[0].mv.col = x->ss[0].mv.row = 0;
-  x->ss[0].offset = 0;
+  cfg->ss[0].mv.col = cfg->ss[0].mv.row = 0;
+  cfg->ss[0].offset = 0;
 
   for (len = MAX_FIRST_STEP; len > 0; len /= 2) {
     // Generate offsets for 4 search sites per step.
     const MV ss_mvs[] = {{-len, 0}, {len, 0}, {0, -len}, {0, len}};
     int i;
     for (i = 0; i < 4; ++i) {
-      search_site *const ss = &x->ss[ss_count++];
+      search_site *const ss = &cfg->ss[ss_count++];
       ss->mv = ss_mvs[i];
       ss->offset = ss->mv.row * stride + ss->mv.col;
     }
   }
 
-  x->ss_count = ss_count;
-  x->searches_per_step = 4;
+  cfg->ss_count = ss_count;
+  cfg->searches_per_step = 4;
 }
 
-void vp9_init3smotion_compensation(MACROBLOCK *x, int stride) {
+void vp9_init3smotion_compensation(search_site_config *cfg, int stride) {
   int len, ss_count = 1;
 
-  x->ss[0].mv.col = x->ss[0].mv.row = 0;
-  x->ss[0].offset = 0;
+  cfg->ss[0].mv.col = cfg->ss[0].mv.row = 0;
+  cfg->ss[0].offset = 0;
 
   for (len = MAX_FIRST_STEP; len > 0; len /= 2) {
     // Generate offsets for 8 search sites per step.
@@ -137,14 +136,14 @@
     };
     int i;
     for (i = 0; i < 8; ++i) {
-      search_site *const ss = &x->ss[ss_count++];
+      search_site *const ss = &cfg->ss[ss_count++];
       ss->mv = ss_mvs[i];
       ss->offset = ss->mv.row * stride + ss->mv.col;
     }
   }
 
-  x->ss_count = ss_count;
-  x->searches_per_step = 8;
+  cfg->ss_count = ss_count;
+  cfg->searches_per_step = 8;
 }
 
 /*
@@ -170,14 +169,13 @@
   return (x & 7) << 1;
 }
 
-static INLINE const uint8_t *pre(const uint8_t *buf, int stride, int r, int c,
-                                 int offset) {
-  return &buf[(r >> 3) * stride + (c >> 3) - offset];
+static INLINE const uint8_t *pre(const uint8_t *buf, int stride, int r, int c) {
+  return &buf[(r >> 3) * stride + (c >> 3)];
 }
 
 /* returns subpixel variance error function */
 #define DIST(r, c) \
-    vfp->svf(pre(y, y_stride, r, c, offset), y_stride, sp(c), sp(r), z, \
+    vfp->svf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, \
              src_stride, &sse)
 
 /* checks if (r, c) has better score than previous best */
@@ -270,7 +268,7 @@
                                  int *mvjcost, int *mvcost[2],
                                  int *distortion,
                                  unsigned int *sse1) {
-  const uint8_t *z = x->plane[0].src.buf;
+  const uint8_t *const z = x->plane[0].src.buf;
   const int src_stride = x->plane[0].src.stride;
   const MACROBLOCKD *xd = &x->e_mbd;
   unsigned int besterr = INT_MAX;
@@ -283,7 +281,7 @@
 
   const int y_stride = xd->plane[0].pre[0].stride;
   const int offset = bestmv->row * y_stride + bestmv->col;
-  const uint8_t *y = xd->plane[0].pre[0].buf + offset;
+  const uint8_t *const y = xd->plane[0].pre[0].buf;
 
   int rr = ref_mv->row;
   int rc = ref_mv->col;
@@ -303,7 +301,7 @@
   bestmv->col *= 8;
 
   // calculate central point error
-  besterr = vfp->vf(y, y_stride, z, src_stride, sse1);
+  besterr = vfp->vf(y + offset, y_stride, z, src_stride, sse1);
   *distortion = besterr;
   besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
 
@@ -353,7 +351,7 @@
 #undef DIST
 /* returns subpixel variance error function */
 #define DIST(r, c) \
-    vfp->svaf(pre(y, y_stride, r, c, offset), y_stride, sp(c), sp(r), \
+    vfp->svaf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), \
               z, src_stride, &sse, second_pred)
 
 int vp9_find_best_sub_pixel_comp_tree(const MACROBLOCK *x,
@@ -368,7 +366,7 @@
                                       unsigned int *sse1,
                                       const uint8_t *second_pred,
                                       int w, int h) {
-  const uint8_t *z = x->plane[0].src.buf;
+  const uint8_t *const z = x->plane[0].src.buf;
   const int src_stride = x->plane[0].src.stride;
   const MACROBLOCKD *xd = &x->e_mbd;
   unsigned int besterr = INT_MAX;
@@ -382,7 +380,7 @@
   DECLARE_ALIGNED_ARRAY(16, uint8_t, comp_pred, 64 * 64);
   const int y_stride = xd->plane[0].pre[0].stride;
   const int offset = bestmv->row * y_stride + bestmv->col;
-  const uint8_t *y = xd->plane[0].pre[0].buf + offset;
+  const uint8_t *const y = xd->plane[0].pre[0].buf;
 
   int rr = ref_mv->row;
   int rc = ref_mv->col;
@@ -404,7 +402,7 @@
   // calculate central point error
   // TODO(yunqingwang): central pointer error was already calculated in full-
   // pixel search, and can be passed in this function.
-  vp9_comp_avg_pred(comp_pred, second_pred, w, h, y, y_stride);
+  vp9_comp_avg_pred(comp_pred, second_pred, w, h, y + offset, y_stride);
   besterr = vfp->vf(comp_pred, w, z, src_stride, sse1);
   *distortion = besterr;
   besterr += mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
@@ -479,8 +477,7 @@
   {\
     if (thissad < bestsad) {\
       if (use_mvcost) \
-        thissad += mvsad_err_cost(&this_mv, &fcenter_mv, \
-                                  mvjsadcost, mvsadcost, sad_per_bit);\
+        thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit);\
       if (thissad < bestsad) {\
         bestsad = thissad;\
         best_site = i;\
@@ -520,9 +517,6 @@
   int k = -1;
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
   int best_init_s = search_param_to_steps[search_param];
-  const int *const mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
-
   // adjust ref_mv to make sure it is within MV range
   clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max);
   br = ref_mv->row;
@@ -531,8 +525,8 @@
   // Work out the start point for the search
   bestsad = vfp->sdf(what->buf, what->stride,
                      get_buf_from_mv(in_what, ref_mv), in_what->stride,
-                     0x7fffffff) + mvsad_err_cost(ref_mv, &fcenter_mv,
-                         mvjsadcost, mvsadcost, sad_per_bit);
+                     0x7fffffff) + mvsad_err_cost(x, ref_mv, &fcenter_mv,
+                                                  sad_per_bit);
 
   // Search all possible scales upto the search param around the center point
   // pick the scale of the point that is best as the starting scale of
@@ -877,10 +871,11 @@
 
 #undef CHECK_BETTER
 
-int vp9_full_range_search_c(const MACROBLOCK *x, MV *ref_mv, MV *best_mv,
+int vp9_full_range_search_c(const MACROBLOCK *x,
+                            const search_site_config *cfg,
+                            MV *ref_mv, MV *best_mv,
                             int search_param, int sad_per_bit, int *num00,
                             const vp9_variance_fn_ptr_t *fn_ptr,
-                            int *mvjcost, int *mvcost[2],
                             const MV *center_mv) {
   const MACROBLOCKD *const xd = &x->e_mbd;
   const uint8_t *what = x->plane[0].src.buf;
@@ -893,10 +888,6 @@
 
   unsigned int thissad;
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
-
   int tr, tc;
   int best_tr = 0;
   int best_tc = 0;
@@ -918,8 +909,7 @@
 
   // Check the starting position
   bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff)
-                + mvsad_err_cost(best_mv, &fcenter_mv,
-                                 mvjsadcost, mvsadcost, sad_per_bit);
+                + mvsad_err_cost(x, best_mv, &fcenter_mv, sad_per_bit);
 
   start_row = MAX(-range, x->mv_row_min - ref_row);
   start_col = MAX(-range, x->mv_col_min - ref_col);
@@ -940,8 +930,7 @@
           if (sad_array[i] < bestsad) {
             const MV this_mv = {ref_row + tr, ref_col + tc + i};
             thissad = sad_array[i] +
-                      mvsad_err_cost(&this_mv, &fcenter_mv,
-                                      mvjsadcost, mvsadcost, sad_per_bit);
+                      mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit);
             if (thissad < bestsad) {
               bestsad = thissad;
               best_tr = tr;
@@ -957,8 +946,7 @@
 
           if (thissad < bestsad) {
             const MV this_mv = {ref_row + tr, ref_col + tc + i};
-            thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                      mvjsadcost, mvsadcost, sad_per_bit);
+            thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit);
 
             if (thissad < bestsad) {
               bestsad = thissad;
@@ -976,10 +964,10 @@
 }
 
 int vp9_diamond_search_sad_c(const MACROBLOCK *x,
+                             const search_site_config *cfg,
                              MV *ref_mv, MV *best_mv,
                              int search_param, int sad_per_bit, int *num00,
                              const vp9_variance_fn_ptr_t *fn_ptr,
-                             int *mvjcost, int *mvcost[2],
                              const MV *center_mv) {
   const MACROBLOCKD *const xd = &x->e_mbd;
   const struct buf_2d *const what = &x->plane[0].src;
@@ -988,31 +976,30 @@
   // of iterations
   // 0 = initial step (MAX_FIRST_STEP) pel : 1 = (MAX_FIRST_STEP/2) pel, 2 =
   // (MAX_FIRST_STEP/4) pel... etc.
-  const search_site *const ss = &x->ss[search_param * x->searches_per_step];
-  const int tot_steps = (x->ss_count / x->searches_per_step) - search_param;
+  const search_site *const ss = &cfg->ss[search_param * cfg->searches_per_step];
+  const int tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param;
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
-  const uint8_t *best_address;
+  const uint8_t *best_address, *in_what_ref;
   int best_sad = INT_MAX;
   int best_site = 0;
   int last_site = 0;
   int i, j, step;
 
   clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max);
-  best_address = get_buf_from_mv(in_what, ref_mv);
+  in_what_ref = get_buf_from_mv(in_what, ref_mv);
+  best_address = in_what_ref;
   *num00 = 0;
   *best_mv = *ref_mv;
 
   // Check the starting position
   best_sad = fn_ptr->sdf(what->buf, what->stride,
-                        in_what->buf, in_what->stride, 0x7fffffff) +
-      mvsad_err_cost(best_mv, &fcenter_mv, mvjsadcost, mvsadcost, sad_per_bit);
+                         best_address, in_what->stride, 0x7fffffff) +
+      mvsad_err_cost(x, best_mv, &fcenter_mv, sad_per_bit);
 
   i = 1;
 
   for (step = 0; step < tot_steps; step++) {
-    for (j = 0; j < x->searches_per_step; j++) {
+    for (j = 0; j < cfg->searches_per_step; j++) {
       const MV mv = {best_mv->row + ss[i].mv.row,
                      best_mv->col + ss[i].mv.col};
       if (is_mv_in(x, &mv)) {
@@ -1020,8 +1007,7 @@
                              best_address + ss[i].offset, in_what->stride,
                              best_sad);
         if (sad < best_sad) {
-          sad += mvsad_err_cost(&mv, &fcenter_mv, mvjsadcost, mvsadcost,
-                                sad_per_bit);
+          sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
           if (sad < best_sad) {
             best_sad = sad;
             best_site = i;
@@ -1046,8 +1032,7 @@
                                 best_address + ss[best_site].offset,
                                 in_what->stride, best_sad);
           if (sad < best_sad) {
-            sad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                  mvjsadcost, mvsadcost, sad_per_bit);
+            sad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit);
             if (sad < best_sad) {
               best_sad = sad;
               best_mv->row += ss[best_site].mv.row;
@@ -1060,7 +1045,7 @@
         break;
       };
 #endif
-    } else if (best_address == in_what->buf) {
+    } else if (best_address == in_what_ref) {
       (*num00)++;
     }
   }
@@ -1068,10 +1053,10 @@
 }
 
 int vp9_diamond_search_sadx4(const MACROBLOCK *x,
+                             const search_site_config *cfg,
                              MV *ref_mv, MV *best_mv, int search_param,
                              int sad_per_bit, int *num00,
                              const vp9_variance_fn_ptr_t *fn_ptr,
-                             int *mvjcost, int *mvcost[2],
                              const MV *center_mv) {
   int i, j, step;
 
@@ -1094,14 +1079,10 @@
   // 0 = initial step (MAX_FIRST_STEP) pel
   // 1 = (MAX_FIRST_STEP/2) pel,
   // 2 = (MAX_FIRST_STEP/4) pel...
-  const search_site *ss = &x->ss[search_param * x->searches_per_step];
-  const int tot_steps = (x->ss_count / x->searches_per_step) - search_param;
+  const search_site *ss = &cfg->ss[search_param * cfg->searches_per_step];
+  const int tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param;
 
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
-
   clamp_mv(ref_mv, x->mv_col_min, x->mv_col_max, x->mv_row_min, x->mv_row_max);
   ref_row = ref_mv->row;
   ref_col = ref_mv->col;
@@ -1115,8 +1096,7 @@
 
   // Check the starting position
   bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride, 0x7fffffff)
-                + mvsad_err_cost(best_mv, &fcenter_mv,
-                                 mvjsadcost, mvsadcost, sad_per_bit);
+                + mvsad_err_cost(x, best_mv, &fcenter_mv, sad_per_bit);
 
   i = 1;
 
@@ -1136,7 +1116,7 @@
     if (all_in) {
       unsigned int sad_array[4];
 
-      for (j = 0; j < x->searches_per_step; j += 4) {
+      for (j = 0; j < cfg->searches_per_step; j += 4) {
         unsigned char const *block_offset[4];
 
         for (t = 0; t < 4; t++)
@@ -1149,9 +1129,8 @@
           if (sad_array[t] < bestsad) {
             const MV this_mv = {best_mv->row + ss[i].mv.row,
                                 best_mv->col + ss[i].mv.col};
-            sad_array[t] += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                           mvjsadcost, mvsadcost, sad_per_bit);
-
+            sad_array[t] += mvsad_err_cost(x, &this_mv, &fcenter_mv,
+                                           sad_per_bit);
             if (sad_array[t] < bestsad) {
               bestsad = sad_array[t];
               best_site = i;
@@ -1160,7 +1139,7 @@
         }
       }
     } else {
-      for (j = 0; j < x->searches_per_step; j++) {
+      for (j = 0; j < cfg->searches_per_step; j++) {
         // Trap illegal vectors
         const MV this_mv = {best_mv->row + ss[i].mv.row,
                             best_mv->col + ss[i].mv.col};
@@ -1171,9 +1150,7 @@
                                              in_what_stride, bestsad);
 
           if (thissad < bestsad) {
-            thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                      mvjsadcost, mvsadcost, sad_per_bit);
-
+            thissad += mvsad_err_cost(x, &this_mv, &fcenter_mv, sad_per_bit);
             if (thissad < bestsad) {
               bestsad = thissad;
               best_site = i;
@@ -1229,10 +1206,9 @@
                            const MV *ref_mv, MV *dst_mv) {
   MV temp_mv;
   int thissme, n, num00 = 0;
-  int bestsme = cpi->diamond_search_sad(x, mvp_full, &temp_mv,
+  int bestsme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
                                         step_param, sadpb, &n,
-                                        fn_ptr, x->nmvjointcost,
-                                        x->mvcost, ref_mv);
+                                        fn_ptr, ref_mv);
   if (bestsme < INT_MAX)
     bestsme = vp9_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1);
   *dst_mv = temp_mv;
@@ -1248,10 +1224,9 @@
     if (num00) {
       num00--;
     } else {
-      thissme = cpi->diamond_search_sad(x, mvp_full, &temp_mv,
+      thissme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
                                         step_param + n, sadpb, &num00,
-                                        fn_ptr, x->nmvjointcost, x->mvcost,
-                                        ref_mv);
+                                        fn_ptr, ref_mv);
       if (thissme < INT_MAX)
         thissme = vp9_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1);
 
@@ -1271,8 +1246,7 @@
     const int search_range = 8;
     MV best_mv = *dst_mv;
     thissme = cpi->refining_search_sad(x, &best_mv, sadpb, search_range,
-                                       fn_ptr, x->nmvjointcost, x->mvcost,
-                                       ref_mv);
+                                       fn_ptr, ref_mv);
     if (thissme < INT_MAX)
       thissme = vp9_get_mvpred_var(x, &best_mv, ref_mv, fn_ptr, 1);
     if (thissme < bestsme) {
@@ -1286,7 +1260,6 @@
 int vp9_full_search_sad_c(const MACROBLOCK *x, const MV *ref_mv,
                           int sad_per_bit, int distance,
                           const vp9_variance_fn_ptr_t *fn_ptr,
-                          int *mvjcost, int *mvcost[2],
                           const MV *center_mv, MV *best_mv) {
   int r, c;
   const MACROBLOCKD *const xd = &x->e_mbd;
@@ -1296,12 +1269,10 @@
   const int row_max = MIN(ref_mv->row + distance, x->mv_row_max);
   const int col_min = MAX(ref_mv->col - distance, x->mv_col_min);
   const int col_max = MIN(ref_mv->col + distance, x->mv_col_max);
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
   int best_sad = fn_ptr->sdf(what->buf, what->stride,
       get_buf_from_mv(in_what, ref_mv), in_what->stride, 0x7fffffff) +
-      mvsad_err_cost(ref_mv, &fcenter_mv, mvjsadcost, mvsadcost, sad_per_bit);
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, sad_per_bit);
   *best_mv = *ref_mv;
 
   for (r = row_min; r < row_max; ++r) {
@@ -1309,9 +1280,7 @@
       const MV mv = {r, c};
       const int sad = fn_ptr->sdf(what->buf, what->stride,
           get_buf_from_mv(in_what, &mv), in_what->stride, best_sad) +
-          mvsad_err_cost(&mv, &fcenter_mv, mvjsadcost, mvsadcost,
-                         sad_per_bit);
-
+              mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
       if (sad < best_sad) {
         best_sad = sad;
         *best_mv = mv;
@@ -1324,232 +1293,171 @@
 int vp9_full_search_sadx3(const MACROBLOCK *x, const MV *ref_mv,
                           int sad_per_bit, int distance,
                           const vp9_variance_fn_ptr_t *fn_ptr,
-                          int *mvjcost, int *mvcost[2],
                           const MV *center_mv, MV *best_mv) {
+  int r;
   const MACROBLOCKD *const xd = &x->e_mbd;
-  const uint8_t *const what = x->plane[0].src.buf;
-  const int what_stride = x->plane[0].src.stride;
-  const uint8_t *const in_what = xd->plane[0].pre[0].buf;
-  const int in_what_stride = xd->plane[0].pre[0].stride;
-  MV this_mv;
-  unsigned int bestsad = INT_MAX;
-  int r, c;
-  unsigned int thissad;
-  int ref_row = ref_mv->row;
-  int ref_col = ref_mv->col;
-
-  // Apply further limits to prevent us looking using vectors that stretch
-  // beyond the UMV border
-  const int row_min = MAX(ref_row - distance, x->mv_row_min);
-  const int row_max = MIN(ref_row + distance, x->mv_row_max);
-  const int col_min = MAX(ref_col - distance, x->mv_col_min);
-  const int col_max = MIN(ref_col + distance, x->mv_col_max);
-  unsigned int sad_array[3];
+  const struct buf_2d *const what = &x->plane[0].src;
+  const struct buf_2d *const in_what = &xd->plane[0].pre[0];
+  const int row_min = MAX(ref_mv->row - distance, x->mv_row_min);
+  const int row_max = MIN(ref_mv->row + distance, x->mv_row_max);
+  const int col_min = MAX(ref_mv->col - distance, x->mv_col_min);
+  const int col_max = MIN(ref_mv->col + distance, x->mv_col_max);
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
+  unsigned int best_sad = fn_ptr->sdf(what->buf, what->stride,
+      get_buf_from_mv(in_what, ref_mv), in_what->stride, 0x7fffffff) +
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, sad_per_bit);
+  *best_mv = *ref_mv;
 
-  // Work out the mid point for the search
-  const uint8_t *bestaddress = &in_what[ref_row * in_what_stride + ref_col];
+  for (r = row_min; r < row_max; ++r) {
+    int c = col_min;
+    const uint8_t *check_here = &in_what->buf[r * in_what->stride + c];
 
-  best_mv->row = ref_row;
-  best_mv->col = ref_col;
+    if (fn_ptr->sdx3f != NULL) {
+      while ((c + 2) < col_max) {
+        int i;
+        unsigned int sads[3];
 
-  // Baseline value at the centre
-  bestsad = fn_ptr->sdf(what, what_stride,
-                        bestaddress, in_what_stride, 0x7fffffff)
-            + mvsad_err_cost(best_mv, &fcenter_mv,
-                             mvjsadcost, mvsadcost, sad_per_bit);
+        fn_ptr->sdx3f(what->buf, what->stride, check_here, in_what->stride,
+                      sads);
 
-  for (r = row_min; r < row_max; r++) {
-    const uint8_t *check_here = &in_what[r * in_what_stride + col_min];
-    this_mv.row = r;
-    c = col_min;
-
-    while ((c + 2) < col_max && fn_ptr->sdx3f != NULL) {
-      int i;
-
-      fn_ptr->sdx3f(what, what_stride, check_here, in_what_stride, sad_array);
-
-      for (i = 0; i < 3; i++) {
-        thissad = sad_array[i];
-
-        if (thissad < bestsad) {
-          this_mv.col = c;
-          thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                    mvjsadcost, mvsadcost, sad_per_bit);
-
-          if (thissad < bestsad) {
-            bestsad = thissad;
-            best_mv->row = r;
-            best_mv->col = c;
+        for (i = 0; i < 3; ++i) {
+          unsigned int sad = sads[i];
+          if (sad < best_sad) {
+            const MV mv = {r, c};
+            sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
+            if (sad < best_sad) {
+              best_sad = sad;
+              *best_mv = mv;
+            }
           }
+          ++check_here;
+          ++c;
         }
-        check_here++;
-        c++;
       }
     }
 
     while (c < col_max) {
-      thissad = fn_ptr->sdf(what, what_stride, check_here, in_what_stride,
-                            bestsad);
-
-      if (thissad < bestsad) {
-        this_mv.col = c;
-        thissad  += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                   mvjsadcost, mvsadcost, sad_per_bit);
-
-        if (thissad < bestsad) {
-          bestsad = thissad;
-          best_mv->row = r;
-          best_mv->col = c;
+      unsigned int sad = fn_ptr->sdf(what->buf, what->stride,
+                                     check_here, in_what->stride, best_sad);
+      if (sad < best_sad) {
+        const MV mv = {r, c};
+        sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
+        if (sad < best_sad) {
+          best_sad = sad;
+          *best_mv = mv;
         }
       }
-
-      check_here++;
-      c++;
+      ++check_here;
+      ++c;
     }
   }
-  return bestsad;
+
+  return best_sad;
 }
 
 int vp9_full_search_sadx8(const MACROBLOCK *x, const MV *ref_mv,
                           int sad_per_bit, int distance,
                           const vp9_variance_fn_ptr_t *fn_ptr,
-                          int *mvjcost, int *mvcost[2],
                           const MV *center_mv, MV *best_mv) {
+  int r;
   const MACROBLOCKD *const xd = &x->e_mbd;
-  const uint8_t *const what = x->plane[0].src.buf;
-  const int what_stride = x->plane[0].src.stride;
-  const uint8_t *const in_what = xd->plane[0].pre[0].buf;
-  const int in_what_stride = xd->plane[0].pre[0].stride;
-  MV this_mv;
-  unsigned int bestsad = INT_MAX;
-  int r, c;
-  int ref_row = ref_mv->row;
-  int ref_col = ref_mv->col;
-
-  // Apply further limits to prevent us looking using vectors that stretch
-  // beyond the UMV border
-  const int row_min = MAX(ref_row - distance, x->mv_row_min);
-  const int row_max = MIN(ref_row + distance, x->mv_row_max);
-  const int col_min = MAX(ref_col - distance, x->mv_col_min);
-  const int col_max = MIN(ref_col + distance, x->mv_col_max);
-  DECLARE_ALIGNED_ARRAY(16, uint32_t, sad_array8, 8);
-  unsigned int sad_array[3];
+  const struct buf_2d *const what = &x->plane[0].src;
+  const struct buf_2d *const in_what = &xd->plane[0].pre[0];
+  const int row_min = MAX(ref_mv->row - distance, x->mv_row_min);
+  const int row_max = MIN(ref_mv->row + distance, x->mv_row_max);
+  const int col_min = MAX(ref_mv->col - distance, x->mv_col_min);
+  const int col_max = MIN(ref_mv->col + distance, x->mv_col_max);
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
+  unsigned int best_sad = fn_ptr->sdf(what->buf, what->stride,
+      get_buf_from_mv(in_what, ref_mv), in_what->stride, 0x7fffffff) +
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, sad_per_bit);
+  *best_mv = *ref_mv;
 
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
+  for (r = row_min; r < row_max; ++r) {
+    int c = col_min;
+    const uint8_t *check_here = &in_what->buf[r * in_what->stride + c];
 
-  // Work out the mid point for the search
-  const uint8_t *bestaddress = &in_what[ref_row * in_what_stride + ref_col];
+    if (fn_ptr->sdx8f != NULL) {
+      while ((c + 7) < col_max) {
+        int i;
+        unsigned int sads[8];
 
-  best_mv->row = ref_row;
-  best_mv->col = ref_col;
+        fn_ptr->sdx8f(what->buf, what->stride, check_here, in_what->stride,
+                      sads);
 
-  // Baseline value at the center
-  bestsad = fn_ptr->sdf(what, what_stride,
-                        bestaddress, in_what_stride, 0x7fffffff)
-            + mvsad_err_cost(best_mv, &fcenter_mv,
-                             mvjsadcost, mvsadcost, sad_per_bit);
-
-  for (r = row_min; r < row_max; r++) {
-    const uint8_t *check_here = &in_what[r * in_what_stride + col_min];
-    this_mv.row = r;
-    c = col_min;
-
-    while ((c + 7) < col_max) {
-      int i;
-
-      fn_ptr->sdx8f(what, what_stride, check_here, in_what_stride, sad_array8);
-
-      for (i = 0; i < 8; i++) {
-        unsigned int thissad = (unsigned int)sad_array8[i];
-
-        if (thissad < bestsad) {
-          this_mv.col = c;
-          thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                    mvjsadcost, mvsadcost, sad_per_bit);
-
-          if (thissad < bestsad) {
-            bestsad = thissad;
-            best_mv->row = r;
-            best_mv->col = c;
+        for (i = 0; i < 8; ++i) {
+          unsigned int sad = sads[i];
+          if (sad < best_sad) {
+            const MV mv = {r, c};
+            sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
+            if (sad < best_sad) {
+              best_sad = sad;
+              *best_mv = mv;
+            }
           }
+          ++check_here;
+          ++c;
         }
-
-        check_here++;
-        c++;
       }
     }
 
-    while ((c + 2) < col_max && fn_ptr->sdx3f != NULL) {
-      int i;
+    if (fn_ptr->sdx3f != NULL) {
+      while ((c + 2) < col_max) {
+        int i;
+        unsigned int sads[3];
 
-      fn_ptr->sdx3f(what, what_stride, check_here, in_what_stride, sad_array);
+        fn_ptr->sdx3f(what->buf, what->stride, check_here, in_what->stride,
+                      sads);
 
-      for (i = 0; i < 3; i++) {
-        unsigned int thissad = sad_array[i];
-
-        if (thissad < bestsad) {
-          this_mv.col = c;
-          thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                    mvjsadcost, mvsadcost, sad_per_bit);
-
-          if (thissad < bestsad) {
-            bestsad = thissad;
-            best_mv->row = r;
-            best_mv->col = c;
+        for (i = 0; i < 3; ++i) {
+          unsigned int sad = sads[i];
+          if (sad < best_sad) {
+            const MV mv = {r, c};
+            sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
+            if (sad < best_sad) {
+              best_sad = sad;
+              *best_mv = mv;
+            }
           }
+          ++check_here;
+          ++c;
         }
-
-        check_here++;
-        c++;
       }
     }
 
     while (c < col_max) {
-      unsigned int thissad = fn_ptr->sdf(what, what_stride,
-                                         check_here, in_what_stride, bestsad);
-
-      if (thissad < bestsad) {
-        this_mv.col = c;
-        thissad += mvsad_err_cost(&this_mv, &fcenter_mv,
-                                  mvjsadcost, mvsadcost, sad_per_bit);
-
-        if (thissad < bestsad) {
-          bestsad = thissad;
-          best_mv->row = r;
-          best_mv->col = c;
+      unsigned int sad = fn_ptr->sdf(what->buf, what->stride,
+                                     check_here, in_what->stride, best_sad);
+      if (sad < best_sad) {
+        const MV mv = {r, c};
+        sad += mvsad_err_cost(x, &mv, &fcenter_mv, sad_per_bit);
+        if (sad < best_sad) {
+          best_sad = sad;
+          *best_mv = mv;
         }
       }
-
-      check_here++;
-      c++;
+      ++check_here;
+      ++c;
     }
   }
-  return bestsad;
+
+  return best_sad;
 }
 
 int vp9_refining_search_sad_c(const MACROBLOCK *x,
                               MV *ref_mv, int error_per_bit,
                               int search_range,
                               const vp9_variance_fn_ptr_t *fn_ptr,
-                              int *mvjcost, int *mvcost[2],
                               const MV *center_mv) {
   const MV neighbors[4] = {{ -1, 0}, {0, -1}, {0, 1}, {1, 0}};
   const MACROBLOCKD *const xd = &x->e_mbd;
   const struct buf_2d *const what = &x->plane[0].src;
   const struct buf_2d *const in_what = &xd->plane[0].pre[0];
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
-
   unsigned int best_sad = fn_ptr->sdf(what->buf, what->stride,
                                      get_buf_from_mv(in_what, ref_mv),
                                      in_what->stride, 0x7fffffff) +
-      mvsad_err_cost(ref_mv, &fcenter_mv, mvjsadcost, mvsadcost, error_per_bit);
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, error_per_bit);
   int i, j;
 
   for (i = 0; i < search_range; i++) {
@@ -1562,8 +1470,7 @@
         unsigned int sad = fn_ptr->sdf(what->buf, what->stride,
             get_buf_from_mv(in_what, &mv), in_what->stride, best_sad);
         if (sad < best_sad) {
-          sad += mvsad_err_cost(&mv, &fcenter_mv, mvjsadcost, mvsadcost,
-                                error_per_bit);
+          sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit);
           if (sad < best_sad) {
             best_sad = sad;
             best_site = j;
@@ -1586,19 +1493,16 @@
                               MV *ref_mv, int error_per_bit,
                               int search_range,
                               const vp9_variance_fn_ptr_t *fn_ptr,
-                              int *mvjcost, int *mvcost[2],
                               const MV *center_mv) {
   const MACROBLOCKD *const xd = &x->e_mbd;
   const MV neighbors[4] = {{ -1, 0}, {0, -1}, {0, 1}, {1, 0}};
   const struct buf_2d *const what = &x->plane[0].src;
   const struct buf_2d *const in_what = &xd->plane[0].pre[0];
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
   const uint8_t *best_address = get_buf_from_mv(in_what, ref_mv);
   unsigned int best_sad = fn_ptr->sdf(what->buf, what->stride, best_address,
                                     in_what->stride, 0x7fffffff) +
-      mvsad_err_cost(ref_mv, &fcenter_mv, mvjsadcost, mvsadcost, error_per_bit);
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, error_per_bit);
   int i, j;
 
   for (i = 0; i < search_range; i++) {
@@ -1623,9 +1527,7 @@
         if (sads[j] < best_sad) {
           const MV mv = {ref_mv->row + neighbors[j].row,
                          ref_mv->col + neighbors[j].col};
-          sads[j] += mvsad_err_cost(&mv, &fcenter_mv,
-                                         mvjsadcost, mvsadcost, error_per_bit);
-
+          sads[j] += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit);
           if (sads[j] < best_sad) {
             best_sad = sads[j];
             best_site = j;
@@ -1642,9 +1544,7 @@
                                          get_buf_from_mv(in_what, &mv),
                                          in_what->stride, best_sad);
           if (sad < best_sad) {
-            sad += mvsad_err_cost(&mv, &fcenter_mv,
-                                  mvjsadcost, mvsadcost, error_per_bit);
-
+            sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit);
             if (sad < best_sad) {
               best_sad = sad;
               best_site = j;
@@ -1672,7 +1572,6 @@
                              MV *ref_mv, int error_per_bit,
                              int search_range,
                              const vp9_variance_fn_ptr_t *fn_ptr,
-                             int *mvjcost, int *mvcost[2],
                              const MV *center_mv,
                              const uint8_t *second_pred, int w, int h) {
   const MV neighbors[8] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0},
@@ -1681,12 +1580,10 @@
   const struct buf_2d *const what = &x->plane[0].src;
   const struct buf_2d *const in_what = &xd->plane[0].pre[0];
   const MV fcenter_mv = {center_mv->row >> 3, center_mv->col >> 3};
-  const int *mvjsadcost = x->nmvjointsadcost;
-  int *mvsadcost[2] = {x->nmvsadcost[0], x->nmvsadcost[1]};
   unsigned int best_sad = fn_ptr->sdaf(what->buf, what->stride,
       get_buf_from_mv(in_what, ref_mv), in_what->stride,
       second_pred, 0x7fffffff) +
-      mvsad_err_cost(ref_mv, &fcenter_mv, mvjsadcost, mvsadcost, error_per_bit);
+      mvsad_err_cost(x, ref_mv, &fcenter_mv, error_per_bit);
   int i, j;
 
   for (i = 0; i < search_range; ++i) {
@@ -1701,8 +1598,7 @@
             get_buf_from_mv(in_what, &mv), in_what->stride,
             second_pred, best_sad);
         if (sad < best_sad) {
-          sad += mvsad_err_cost(&mv, &fcenter_mv,
-                                    mvjsadcost, mvsadcost, error_per_bit);
+          sad += mvsad_err_cost(x, &mv, &fcenter_mv, error_per_bit);
           if (sad < best_sad) {
             best_sad = sad;
             best_site = j;
diff --git a/vp9/encoder/vp9_mcomp.h b/vp9/encoder/vp9_mcomp.h
index f7b7c5e..1f524f1 100644
--- a/vp9/encoder/vp9_mcomp.h
+++ b/vp9/encoder/vp9_mcomp.h
@@ -31,6 +31,20 @@
 // for Block_16x16
 #define BORDER_MV_PIXELS_B16 (16 + VP9_INTERP_EXTEND)
 
+// motion search site
+typedef struct search_site {
+  MV mv;
+  int offset;
+} search_site;
+
+typedef struct search_site_config {
+  search_site ss[8 * MAX_MVSEARCH_STEPS + 1];
+  int ss_count;
+  int searches_per_step;
+} search_site_config;
+
+void vp9_init_dsmotion_compensation(search_site_config *cfg, int stride);
+void vp9_init3smotion_compensation(search_site_config *cfg,  int stride);
 
 void vp9_set_mv_search_range(MACROBLOCK *x, const MV *mv);
 int vp9_mv_bit_cost(const MV *mv, const MV *ref,
@@ -46,8 +60,6 @@
                           const uint8_t *second_pred,
                           const vp9_variance_fn_ptr_t *vfp,
                           int use_mvcost);
-void vp9_init_dsmotion_compensation(MACROBLOCK *x, int stride);
-void vp9_init3smotion_compensation(MACROBLOCK *x,  int stride);
 
 struct VP9_COMP;
 int vp9_init_search_range(struct VP9_COMP *cpi, int size);
@@ -110,29 +122,26 @@
                                     const MV *ref_mv, int sad_per_bit,
                                     int distance,
                                     const vp9_variance_fn_ptr_t *fn_ptr,
-                                    int *mvjcost, int *mvcost[2],
                                     const MV *center_mv, MV *best_mv);
 
 typedef int (*vp9_refining_search_fn_t)(const MACROBLOCK *x,
                                         MV *ref_mv, int sad_per_bit,
                                         int distance,
                                         const vp9_variance_fn_ptr_t *fn_ptr,
-                                        int *mvjcost, int *mvcost[2],
                                         const MV *center_mv);
 
 typedef int (*vp9_diamond_search_fn_t)(const MACROBLOCK *x,
+                                       const search_site_config *cfg,
                                        MV *ref_mv, MV *best_mv,
                                        int search_param, int sad_per_bit,
                                        int *num00,
                                        const vp9_variance_fn_ptr_t *fn_ptr,
-                                       int *mvjcost, int *mvcost[2],
                                        const MV *center_mv);
 
 int vp9_refining_search_8p_c(const MACROBLOCK *x,
                              MV *ref_mv, int error_per_bit,
                              int search_range,
                              const vp9_variance_fn_ptr_t *fn_ptr,
-                             int *mvjcost, int *mvcost[2],
                              const MV *center_mv, const uint8_t *second_pred,
                              int w, int h);
 #ifdef __cplusplus
diff --git a/vp9/encoder/vp9_picklpf.c b/vp9/encoder/vp9_picklpf.c
index 3ac8522..7c42bb8 100644
--- a/vp9/encoder/vp9_picklpf.c
+++ b/vp9/encoder/vp9_picklpf.c
@@ -19,11 +19,11 @@
 #include "vp9/common/vp9_onyxc_int.h"
 #include "vp9/common/vp9_quant_common.h"
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_picklpf.h"
 #include "vp9/encoder/vp9_quantize.h"
 
-static int get_max_filter_level(VP9_COMP *cpi) {
+static int get_max_filter_level(const VP9_COMP *cpi) {
   return cpi->twopass.section_intra_rating > 8 ? MAX_LOOP_FILTER * 3 / 4
                                                : MAX_LOOP_FILTER;
 }
@@ -43,15 +43,15 @@
   return filt_err;
 }
 
-static void search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
-                                int partial_frame) {
-  VP9_COMMON *const cm = &cpi->common;
-  struct loopfilter *const lf = &cm->lf;
+static int search_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
+                               int partial_frame) {
+  const VP9_COMMON *const cm = &cpi->common;
+  const struct loopfilter *const lf = &cm->lf;
   const int min_filter_level = 0;
   const int max_filter_level = get_max_filter_level(cpi);
-  int best_err;
-  int filt_best;
   int filt_direction = 0;
+  int best_err, filt_best;
+
   // Start the search at the previous frame filter level unless it is now out of
   // range.
   int filt_mid = clamp(lf->filter_level, min_filter_level, max_filter_level);
@@ -128,7 +128,7 @@
     }
   }
 
-  lf->filter_level = filt_best;
+  return filt_best;
 }
 
 void vp9_pick_filter_level(const YV12_BUFFER_CONFIG *sd, VP9_COMP *cpi,
@@ -150,6 +150,7 @@
       filt_guess -= 4;
     lf->filter_level = clamp(filt_guess, min_filter_level, max_filter_level);
   } else {
-    search_filter_level(sd, cpi, method == LPF_PICK_FROM_SUBIMAGE);
+    lf->filter_level = search_filter_level(sd, cpi,
+                                           method == LPF_PICK_FROM_SUBIMAGE);
   }
 }
diff --git a/vp9/encoder/vp9_picklpf.h b/vp9/encoder/vp9_picklpf.h
index 7d08ddb..33c490f 100644
--- a/vp9/encoder/vp9_picklpf.h
+++ b/vp9/encoder/vp9_picklpf.h
@@ -16,7 +16,7 @@
 extern "C" {
 #endif
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 struct yv12_buffer_config;
 struct VP9_COMP;
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index f3fe99c..56eb944 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -22,7 +22,7 @@
 #include "vp9/common/vp9_reconinter.h"
 #include "vp9/common/vp9_reconintra.h"
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 #include "vp9/encoder/vp9_rdopt.h"
 
@@ -212,7 +212,7 @@
   MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
   struct macroblock_plane *const p = &x->plane[0];
   struct macroblockd_plane *const pd = &xd->plane[0];
-  MB_PREDICTION_MODE this_mode, best_mode = ZEROMV;
+  PREDICTION_MODE this_mode, best_mode = ZEROMV;
   MV_REFERENCE_FRAME ref_frame, best_ref_frame = LAST_FRAME;
   INTERP_FILTER best_pred_filter = EIGHTTAP;
   int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES];
@@ -233,11 +233,14 @@
   const int64_t intra_mode_cost = 50;
 
   unsigned char segment_id = mbmi->segment_id;
-  const int *const rd_threshes = cpi->rd_threshes[segment_id][bsize];
-  const int *const rd_thresh_freq_fact = cpi->rd_thresh_freq_fact[bsize];
-  // Mode index conversion form THR_MODES to MB_PREDICTION_MODE for a ref frame.
+  const int *const rd_threshes = cpi->rd.threshes[segment_id][bsize];
+  const int *const rd_thresh_freq_fact = cpi->rd.thresh_freq_fact[bsize];
+  // Mode index conversion form THR_MODES to PREDICTION_MODE for a ref frame.
   int mode_idx[MB_MODE_COUNT] = {0};
   INTERP_FILTER filter_ref = SWITCHABLE;
+  int bsl = mi_width_log2_lookup[bsize];
+  int pred_filter_search = (((mi_row + mi_col) >> bsl) +
+                            cpi->sf.chessboard_index) & 0x01;
 
   x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
 
@@ -338,6 +341,7 @@
       // motion vector is at sub-pixel accuracy level for luma component, i.e.,
       // the last three bits are all zeros.
       if ((this_mode == NEWMV || filter_ref == SWITCHABLE) &&
+          pred_filter_search &&
           ((mbmi->mv[0].as_mv.row & 0x07) != 0 ||
            (mbmi->mv[0].as_mv.col & 0x07) != 0)) {
         int64_t tmp_rdcost1 = INT64_MAX;
@@ -414,7 +418,7 @@
 
   // Perform intra prediction search, if the best SAD is above a certain
   // threshold.
-  if (best_rd > inter_mode_thresh) {
+  if (best_rd > inter_mode_thresh && bsize < cpi->sf.max_intra_bsize) {
     for (this_mode = DC_PRED; this_mode <= DC_PRED; ++this_mode) {
       vp9_predict_intra_block(xd, 0, b_width_log2(bsize),
                               mbmi->tx_size, this_mode,
diff --git a/vp9/encoder/vp9_pickmode.h b/vp9/encoder/vp9_pickmode.h
index 05ff187..a9c948d 100644
--- a/vp9/encoder/vp9_pickmode.h
+++ b/vp9/encoder/vp9_pickmode.h
@@ -11,7 +11,7 @@
 #ifndef VP9_ENCODER_VP9_PICKMODE_H_
 #define VP9_ENCODER_VP9_PICKMODE_H_
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/vp9/encoder/vp9_quantize.c b/vp9/encoder/vp9_quantize.c
index 31f3b3e..5206bb6 100644
--- a/vp9/encoder/vp9_quantize.c
+++ b/vp9/encoder/vp9_quantize.c
@@ -15,7 +15,7 @@
 #include "vp9/common/vp9_quant_common.h"
 #include "vp9/common/vp9_seg_common.h"
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_quantize.h"
 #include "vp9/encoder/vp9_rdopt.h"
 
@@ -220,7 +220,7 @@
   const int segment_id = xd->mi[0]->mbmi.segment_id;
   const int qindex = vp9_get_qindex(&cm->seg, segment_id, cm->base_qindex);
   const int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
-  const int zbin = cpi->zbin_mode_boost + x->act_zbin_adj;
+  const int zbin = cpi->zbin_mode_boost;
   int i;
 
   // Y
@@ -242,10 +242,10 @@
   }
 
 #if CONFIG_ALPHA
-  x->plane[3].quant = cpi->a_quant[qindex];
-  x->plane[3].quant_shift = cpi->a_quant_shift[qindex];
-  x->plane[3].zbin = cpi->a_zbin[qindex];
-  x->plane[3].round = cpi->a_round[qindex];
+  x->plane[3].quant = quants->a_quant[qindex];
+  x->plane[3].quant_shift = quants->a_quant_shift[qindex];
+  x->plane[3].zbin = quants->a_zbin[qindex];
+  x->plane[3].round = quants->a_round[qindex];
   x->plane[3].zbin_extra = (int16_t)((cm->a_dequant[qindex][1] * zbin) >> 7);
   xd->plane[3].dequant = cm->a_dequant[qindex];
 #endif
@@ -262,9 +262,9 @@
 void vp9_update_zbin_extra(VP9_COMP *cpi, MACROBLOCK *x) {
   const int qindex = x->q_index;
   const int y_zbin_extra = (cpi->common.y_dequant[qindex][1] *
-                (cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
+                            cpi->zbin_mode_boost) >> 7;
   const int uv_zbin_extra = (cpi->common.uv_dequant[qindex][1] *
-                  (cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
+                             cpi->zbin_mode_boost) >> 7;
 
   x->plane[0].zbin_extra = (int16_t)y_zbin_extra;
   x->plane[1].zbin_extra = (int16_t)uv_zbin_extra;
diff --git a/vp9/encoder/vp9_quantize.h b/vp9/encoder/vp9_quantize.h
index 7a93883..1835e9c 100644
--- a/vp9/encoder/vp9_quantize.h
+++ b/vp9/encoder/vp9_quantize.h
@@ -11,6 +11,7 @@
 #ifndef VP9_ENCODER_VP9_QUANTIZE_H_
 #define VP9_ENCODER_VP9_QUANTIZE_H_
 
+#include "./vpx_config.h"
 #include "vp9/encoder/vp9_block.h"
 
 #ifdef __cplusplus
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index b4e883f..24e75ae 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -27,6 +27,11 @@
 #include "vp9/encoder/vp9_encodemv.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 
+// Max rate target for 1080P and below encodes under normal circumstances
+// (1920 * 1080 / (16 * 16)) * MAX_MB_RATE bits per MB
+#define MAX_MB_RATE 250
+#define MAXRATE_1080P 2025000
+
 #define DEFAULT_KF_BOOST 2000
 #define DEFAULT_GF_BOOST 2000
 
@@ -35,6 +40,8 @@
 #define MIN_BPB_FACTOR 0.005
 #define MAX_BPB_FACTOR 50
 
+#define FRAME_OVERHEAD_BITS 200
+
 // Tables relating active max Q to active min Q
 static int kf_low_motion_minq[QINDEX_RANGE];
 static int kf_high_motion_minq[QINDEX_RANGE];
@@ -74,7 +81,6 @@
 
   for (i = 0; i < QINDEX_RANGE; i++) {
     const double maxq = vp9_convert_qindex_to_q(i);
-
     kf_low_motion_minq[i] = get_minq_index(maxq, 0.000001, -0.0004, 0.15);
     kf_high_motion_minq[i] = get_minq_index(maxq, 0.000002, -0.0012, 0.50);
     gf_low_motion_minq[i] = get_minq_index(maxq, 0.0000015, -0.0009, 0.32);
@@ -112,7 +118,7 @@
 int vp9_rc_clamp_pframe_target_size(const VP9_COMP *const cpi, int target) {
   const RATE_CONTROL *rc = &cpi->rc;
   const int min_frame_target = MAX(rc->min_frame_bandwidth,
-                                   rc->av_per_frame_bandwidth >> 5);
+                                   rc->avg_frame_bandwidth >> 5);
   if (target < min_frame_target)
     target = min_frame_target;
   if (cpi->refresh_golden_frame && rc->is_src_frame_alt_ref) {
@@ -130,10 +136,10 @@
 
 int vp9_rc_clamp_iframe_target_size(const VP9_COMP *const cpi, int target) {
   const RATE_CONTROL *rc = &cpi->rc;
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
   if (oxcf->rc_max_intra_bitrate_pct) {
-    const int max_rate = rc->av_per_frame_bandwidth *
-        oxcf->rc_max_intra_bitrate_pct / 100;
+    const int max_rate = rc->avg_frame_bandwidth *
+                             oxcf->rc_max_intra_bitrate_pct / 100;
     target = MIN(target, max_rate);
   }
   if (target > rc->max_frame_bandwidth)
@@ -163,27 +169,27 @@
 // Update the buffer level: leaky bucket model.
 static void update_buffer_level(VP9_COMP *cpi, int encoded_frame_size) {
   const VP9_COMMON *const cm = &cpi->common;
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
   RATE_CONTROL *const rc = &cpi->rc;
 
   // Non-viewable frames are a special case and are treated as pure overhead.
   if (!cm->show_frame) {
     rc->bits_off_target -= encoded_frame_size;
   } else {
-    rc->bits_off_target += rc->av_per_frame_bandwidth - encoded_frame_size;
+    rc->bits_off_target += rc->avg_frame_bandwidth - encoded_frame_size;
   }
 
   // Clip the buffer level to the maximum specified buffer size.
   rc->bits_off_target = MIN(rc->bits_off_target, oxcf->maximum_buffer_size);
   rc->buffer_level = rc->bits_off_target;
 
-  if (cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+  if (cpi->use_svc && cpi->oxcf.rc_mode == RC_MODE_CBR) {
     update_layer_buffer_level(&cpi->svc, encoded_frame_size);
   }
 }
 
-void vp9_rc_init(const VP9_CONFIG *oxcf, int pass, RATE_CONTROL *rc) {
-  if (pass == 0 && oxcf->end_usage == USAGE_STREAM_FROM_SERVER) {
+void vp9_rc_init(const VP9EncoderConfig *oxcf, int pass, RATE_CONTROL *rc) {
+  if (pass == 0 && oxcf->rc_mode == RC_MODE_CBR) {
     rc->avg_frame_qindex[0] = oxcf->worst_allowed_q;
     rc->avg_frame_qindex[1] = oxcf->worst_allowed_q;
     rc->avg_frame_qindex[2] = oxcf->worst_allowed_q;
@@ -203,10 +209,10 @@
   rc->buffer_level =    oxcf->starting_buffer_level;
   rc->bits_off_target = oxcf->starting_buffer_level;
 
-  rc->rolling_target_bits      = rc->av_per_frame_bandwidth;
-  rc->rolling_actual_bits      = rc->av_per_frame_bandwidth;
-  rc->long_rolling_target_bits = rc->av_per_frame_bandwidth;
-  rc->long_rolling_actual_bits = rc->av_per_frame_bandwidth;
+  rc->rolling_target_bits      = rc->avg_frame_bandwidth;
+  rc->rolling_actual_bits      = rc->avg_frame_bandwidth;
+  rc->long_rolling_target_bits = rc->avg_frame_bandwidth;
+  rc->long_rolling_actual_bits = rc->avg_frame_bandwidth;
 
   rc->total_actual_bits = 0;
   rc->total_target_vs_actual = 0;
@@ -233,7 +239,7 @@
 }
 
 int vp9_rc_drop_frame(VP9_COMP *cpi) {
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
   RATE_CONTROL *const rc = &cpi->rc;
 
   if (!oxcf->drop_frames_water_mark) {
@@ -276,7 +282,7 @@
   } else {
     if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) &&
         !cpi->rc.is_src_frame_alt_ref &&
-        !(cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER))
+        !(cpi->use_svc && cpi->oxcf.rc_mode == RC_MODE_CBR))
       return cpi->rc.gf_rate_correction_factor;
     else
       return cpi->rc.rate_correction_factor;
@@ -289,7 +295,7 @@
   } else {
     if ((cpi->refresh_alt_ref_frame || cpi->refresh_golden_frame) &&
         !cpi->rc.is_src_frame_alt_ref &&
-        !(cpi->use_svc && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER))
+        !(cpi->use_svc && cpi->oxcf.rc_mode == RC_MODE_CBR))
       cpi->rc.gf_rate_correction_factor = factor;
     else
       cpi->rc.rate_correction_factor = factor;
@@ -304,6 +310,10 @@
 
   int projected_size_based_on_q = 0;
 
+  // Do not update the rate factors for arf overlay frames.
+  if (cpi->rc.is_src_frame_alt_ref)
+    return;
+
   // Clear down mmx registers to allow floating point in what follows
   vp9_clear_system_state();
 
@@ -436,7 +446,7 @@
   // ambient Q (at buffer = optimal level) to worst_quality level
   // (at buffer = critical level).
   const VP9_COMMON *const cm = &cpi->common;
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
   const RATE_CONTROL *rc = &cpi->rc;
   // Buffer level below which we push active_worst to worst_quality.
   int64_t critical_level = oxcf->optimal_buffer_level >> 2;
@@ -565,11 +575,18 @@
 
 #if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
   // Limit Q range for the adaptive loop.
-  if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
-    if (!(cm->current_video_frame == 0))
-      *top_index = (active_worst_quality + active_best_quality * 3) / 4;
+  if (cm->frame_type == KEY_FRAME &&
+      !rc->this_key_frame_forced  &&
+      !(cm->current_video_frame == 0)) {
+    int qdelta = 0;
+    vp9_clear_system_state();
+    qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
+                                        active_worst_quality, 2.0);
+    *top_index = active_worst_quality + qdelta;
+    *top_index = (*top_index > *bottom_index) ? *top_index : *bottom_index;
   }
 #endif
+
   // Special case code to try and match quality with forced key frames
   if (cm->frame_type == KEY_FRAME && rc->this_key_frame_forced) {
     q = rc->last_boosted_qindex;
@@ -597,7 +614,8 @@
                                              int *top_index) {
   const VP9_COMMON *const cm = &cpi->common;
   const RATE_CONTROL *const rc = &cpi->rc;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+  const int cq_level = oxcf->cq_level;
   int active_best_quality;
   int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
   int q;
@@ -655,9 +673,9 @@
       q = rc->avg_frame_qindex[KEY_FRAME];
     }
     // For constrained quality dont allow Q less than the cq level
-    if (oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) {
-      if (q < cpi->cq_target_quality)
-        q = cpi->cq_target_quality;
+    if (oxcf->rc_mode == RC_MODE_CONSTRAINED_QUALITY) {
+      if (q < cq_level)
+        q = cq_level;
       if (rc->frames_since_key > 1) {
         active_best_quality = get_active_quality(q, rc->gfu_boost,
                                                  gf_low, gf_high,
@@ -672,9 +690,9 @@
       // Constrained quality use slightly lower active best.
       active_best_quality = active_best_quality * 15 / 16;
 
-    } else if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+    } else if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
       if (!cpi->refresh_alt_ref_frame) {
-        active_best_quality = cpi->cq_target_quality;
+        active_best_quality = cq_level;
       } else {
         if (rc->frames_since_key > 1) {
           active_best_quality = get_active_quality(
@@ -692,8 +710,8 @@
           gf_low_motion_minq, gf_high_motion_minq);
     }
   } else {
-    if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
-      active_best_quality = cpi->cq_target_quality;
+    if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
+      active_best_quality = cq_level;
     } else {
       // Use the lower of active_worst_quality and recent/average Q.
       if (cm->current_video_frame > 1)
@@ -702,15 +720,9 @@
         active_best_quality = inter_minq[rc->avg_frame_qindex[KEY_FRAME]];
       // For the constrained quality mode we don't want
       // q to fall below the cq level.
-      if ((oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) &&
-          (active_best_quality < cpi->cq_target_quality)) {
-        // If we are strongly undershooting the target rate in the last
-        // frames then use the user passed in cq value not the auto
-        // cq value.
-        if (rc->rolling_actual_bits < rc->min_frame_bandwidth)
-          active_best_quality = oxcf->cq_level;
-        else
-          active_best_quality = cpi->cq_target_quality;
+      if ((oxcf->rc_mode == RC_MODE_CONSTRAINED_QUALITY) &&
+          (active_best_quality < cq_level)) {
+        active_best_quality = cq_level;
       }
     }
   }
@@ -725,16 +737,27 @@
   *bottom_index = active_best_quality;
 
 #if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
-  // Limit Q range for the adaptive loop.
-  if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
-    if (!(cm->current_video_frame == 0))
-      *top_index = (active_worst_quality + active_best_quality * 3) / 4;
-  } else if (!rc->is_src_frame_alt_ref &&
-             (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
-    *top_index = (active_worst_quality + active_best_quality) / 2;
+  {
+    int qdelta = 0;
+    vp9_clear_system_state();
+
+    // Limit Q range for the adaptive loop.
+    if (cm->frame_type == KEY_FRAME &&
+        !rc->this_key_frame_forced &&
+        !(cm->current_video_frame == 0)) {
+      qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
+                                          active_worst_quality, 2.0);
+    } else if (!rc->is_src_frame_alt_ref &&
+               (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+      qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
+                                          active_worst_quality, 1.75);
+    }
+    *top_index = active_worst_quality + qdelta;
+    *top_index = (*top_index > *bottom_index) ? *top_index : *bottom_index;
   }
 #endif
-  if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+
+  if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
     q = active_best_quality;
   // Special case code to try and match quality with forced key frames
   } else if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced) {
@@ -753,7 +776,7 @@
 #if CONFIG_MULTIPLE_ARF
   // Force the quantizer determined by the coding order pattern.
   if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) &&
-      cpi->oxcf.end_usage != USAGE_CONSTANT_QUALITY) {
+      cpi->oxcf.rc_mode != RC_MODE_CONSTANT_QUALITY) {
     double new_q;
     double current_q = vp9_convert_qindex_to_q(active_worst_quality);
     int level = cpi->this_frame_weight;
@@ -780,12 +803,13 @@
                                          int *top_index) {
   const VP9_COMMON *const cm = &cpi->common;
   const RATE_CONTROL *const rc = &cpi->rc;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+  const int cq_level = oxcf->cq_level;
   int active_best_quality;
   int active_worst_quality = cpi->twopass.active_worst_quality;
   int q;
 
-  if (frame_is_intra_only(cm)) {
+  if (frame_is_intra_only(cm) || vp9_is_upper_layer_key_frame(cpi)) {
 #if !CONFIG_MULTIPLE_ARF
     // Handle the special case for key frames forced when we have75 reached
     // the maximum key frame interval. Here force the Q to a range
@@ -840,9 +864,9 @@
       q = active_worst_quality;
     }
     // For constrained quality dont allow Q less than the cq level
-    if (oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) {
-      if (q < cpi->cq_target_quality)
-        q = cpi->cq_target_quality;
+    if (oxcf->rc_mode == RC_MODE_CONSTRAINED_QUALITY) {
+      if (q < cq_level)
+        q = cq_level;
       if (rc->frames_since_key > 1) {
         active_best_quality = get_active_quality(q, rc->gfu_boost,
                                                  gf_low, gf_high,
@@ -857,9 +881,9 @@
       // Constrained quality use slightly lower active best.
       active_best_quality = active_best_quality * 15 / 16;
 
-    } else if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+    } else if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
       if (!cpi->refresh_alt_ref_frame) {
-        active_best_quality = cpi->cq_target_quality;
+        active_best_quality = cq_level;
       } else {
         if (rc->frames_since_key > 1) {
           active_best_quality = get_active_quality(
@@ -877,22 +901,16 @@
           gf_low_motion_minq, gf_high_motion_minq);
     }
   } else {
-    if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
-      active_best_quality = cpi->cq_target_quality;
+    if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
+      active_best_quality = cq_level;
     } else {
       active_best_quality = inter_minq[active_worst_quality];
 
       // For the constrained quality mode we don't want
       // q to fall below the cq level.
-      if ((oxcf->end_usage == USAGE_CONSTRAINED_QUALITY) &&
-          (active_best_quality < cpi->cq_target_quality)) {
-        // If we are strongly undershooting the target rate in the last
-        // frames then use the user passed in cq value not the auto
-        // cq value.
-        if (rc->rolling_actual_bits < rc->min_frame_bandwidth)
-          active_best_quality = oxcf->cq_level;
-        else
-          active_best_quality = cpi->cq_target_quality;
+      if ((oxcf->rc_mode == RC_MODE_CONSTRAINED_QUALITY) &&
+          (active_best_quality < cq_level)) {
+        active_best_quality = cq_level;
       }
     }
   }
@@ -907,17 +925,27 @@
   *bottom_index = active_best_quality;
 
 #if LIMIT_QRANGE_FOR_ALTREF_AND_KEY
-  // Limit Q range for the adaptive loop.
-  if (cm->frame_type == KEY_FRAME && !rc->this_key_frame_forced) {
-    *top_index = (active_worst_quality + active_best_quality * 3) / 4;
-  } else if (!rc->is_src_frame_alt_ref &&
-             (oxcf->end_usage != USAGE_STREAM_FROM_SERVER) &&
-             (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
-    *top_index = (active_worst_quality + active_best_quality) / 2;
+  {
+    int qdelta = 0;
+    vp9_clear_system_state();
+
+    // Limit Q range for the adaptive loop.
+    if ((cm->frame_type == KEY_FRAME || vp9_is_upper_layer_key_frame(cpi)) &&
+        !rc->this_key_frame_forced) {
+      qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
+                                          active_worst_quality, 2.0);
+    } else if (!rc->is_src_frame_alt_ref &&
+               (oxcf->rc_mode != RC_MODE_CBR) &&
+               (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
+      qdelta = vp9_compute_qdelta_by_rate(&cpi->rc, cm->frame_type,
+                                          active_worst_quality, 1.75);
+    }
+    *top_index = active_worst_quality + qdelta;
+    *top_index = (*top_index > *bottom_index) ? *top_index : *bottom_index;
   }
 #endif
 
-  if (oxcf->end_usage == USAGE_CONSTANT_QUALITY) {
+  if (oxcf->rc_mode == RC_MODE_CONSTANT_QUALITY) {
     q = active_best_quality;
   // Special case code to try and match quality with forced key frames.
   } else if ((cm->frame_type == KEY_FRAME) && rc->this_key_frame_forced) {
@@ -936,7 +964,7 @@
 #if CONFIG_MULTIPLE_ARF
   // Force the quantizer determined by the coding order pattern.
   if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) &&
-      cpi->oxcf.end_usage != USAGE_CONSTANT_QUALITY) {
+      cpi->oxcf.rc_mode != RC_MODE_CONSTANT_QUALITY) {
     double new_q;
     double current_q = vp9_convert_qindex_to_q(active_worst_quality);
     int level = cpi->this_frame_weight;
@@ -962,7 +990,7 @@
                              int *bottom_index, int *top_index) {
   int q;
   if (cpi->pass == 0) {
-    if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)
+    if (cpi->oxcf.rc_mode == RC_MODE_CBR)
       q = rc_pick_q_and_bounds_one_pass_cbr(cpi, bottom_index, top_index);
     else
       q = rc_pick_q_and_bounds_one_pass_vbr(cpi, bottom_index, top_index);
@@ -987,31 +1015,19 @@
 }
 
 void vp9_rc_compute_frame_size_bounds(const VP9_COMP *cpi,
-                                      int this_frame_target,
+                                      int frame_target,
                                       int *frame_under_shoot_limit,
                                       int *frame_over_shoot_limit) {
-  // Set-up bounds on acceptable frame size:
-  if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
+  if (cpi->oxcf.rc_mode == RC_MODE_CONSTANT_QUALITY) {
     *frame_under_shoot_limit = 0;
     *frame_over_shoot_limit  = INT_MAX;
   } else {
-    int recode_tolerance =
-      (cpi->sf.recode_tolerance * this_frame_target) / 100;
-
-    *frame_over_shoot_limit = this_frame_target + recode_tolerance;
-    *frame_under_shoot_limit = this_frame_target - recode_tolerance;
-
     // For very small rate targets where the fractional adjustment
     // may be tiny make sure there is at least a minimum range.
-    *frame_over_shoot_limit += 200;
-    *frame_under_shoot_limit -= 200;
-    if (*frame_under_shoot_limit < 0)
-      *frame_under_shoot_limit = 0;
-
-    // Clip to maximum allowed rate for a frame.
-    if (*frame_over_shoot_limit > cpi->rc.max_frame_bandwidth) {
-      *frame_over_shoot_limit = cpi->rc.max_frame_bandwidth;
-    }
+    const int tolerance = (cpi->sf.recode_tolerance * frame_target) / 100;
+    *frame_under_shoot_limit = MAX(frame_target - tolerance - 200, 0);
+    *frame_over_shoot_limit = MIN(frame_target + tolerance + 200,
+                                  cpi->rc.max_frame_bandwidth);
   }
 }
 
@@ -1020,6 +1036,7 @@
   RATE_CONTROL *const rc = &cpi->rc;
 
   rc->this_frame_target = target;
+
   // Target rate per SB64 (including partial SB64s.
   rc->sb64_target_rate = ((int64_t)rc->this_frame_target * 64 * 64) /
                              (cm->width * cm->height);
@@ -1065,40 +1082,39 @@
 }
 
 void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) {
-  VP9_COMMON *const cm = &cpi->common;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9_COMMON *const cm = &cpi->common;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   RATE_CONTROL *const rc = &cpi->rc;
+  const int qindex = cm->base_qindex;
 
-  cm->last_frame_type = cm->frame_type;
   // Update rate control heuristics
   rc->projected_frame_size = (int)(bytes_used << 3);
 
   // Post encode loop adjustment of Q prediction.
   vp9_rc_update_rate_correction_factors(
       cpi, (cpi->sf.recode_loop >= ALLOW_RECODE_KFARFGF ||
-            oxcf->end_usage == USAGE_STREAM_FROM_SERVER) ? 2 : 0);
+            oxcf->rc_mode == RC_MODE_CBR) ? 2 : 0);
 
   // Keep a record of last Q and ambient average Q.
   if (cm->frame_type == KEY_FRAME) {
-    rc->last_q[KEY_FRAME] = cm->base_qindex;
-    rc->avg_frame_qindex[KEY_FRAME] = ROUND_POWER_OF_TWO(
-        3 * rc->avg_frame_qindex[KEY_FRAME] + cm->base_qindex, 2);
+    rc->last_q[KEY_FRAME] = qindex;
+    rc->avg_frame_qindex[KEY_FRAME] =
+        ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[KEY_FRAME] + qindex, 2);
   } else if (!rc->is_src_frame_alt_ref &&
-      (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) &&
-      !(cpi->use_svc && oxcf->end_usage == USAGE_STREAM_FROM_SERVER)) {
-    rc->last_q[2] = cm->base_qindex;
-    rc->avg_frame_qindex[2] = ROUND_POWER_OF_TWO(
-        3 * rc->avg_frame_qindex[2] + cm->base_qindex, 2);
+             (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame) &&
+             !(cpi->use_svc && oxcf->rc_mode == RC_MODE_CBR)) {
+    rc->last_q[2] = qindex;
+    rc->avg_frame_qindex[2] =
+        ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[2] + qindex, 2);
   } else {
-    rc->last_q[INTER_FRAME] = cm->base_qindex;
-    rc->avg_frame_qindex[INTER_FRAME] = ROUND_POWER_OF_TWO(
-        3 * rc->avg_frame_qindex[INTER_FRAME] + cm->base_qindex, 2);
+    rc->last_q[INTER_FRAME] = qindex;
+    rc->avg_frame_qindex[INTER_FRAME] =
+        ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[INTER_FRAME] + qindex, 2);
     rc->ni_frames++;
-    rc->tot_q += vp9_convert_qindex_to_q(cm->base_qindex);
-    rc->avg_q = rc->tot_q / (double)rc->ni_frames;
-
+    rc->tot_q += vp9_convert_qindex_to_q(qindex);
+    rc->avg_q = rc->tot_q / rc->ni_frames;
     // Calculate the average Q for normal inter frames (not key or GFU frames).
-    rc->ni_tot_qi += cm->base_qindex;
+    rc->ni_tot_qi += qindex;
     rc->ni_av_qi = rc->ni_tot_qi / rc->ni_frames;
   }
 
@@ -1107,11 +1123,11 @@
   // If all mbs in this group are skipped only update if the Q value is
   // better than that already stored.
   // This is used to help set quality in forced key frames to reduce popping
-  if ((cm->base_qindex < rc->last_boosted_qindex) ||
+  if ((qindex < rc->last_boosted_qindex) ||
       ((cpi->static_mb_pct < 100) &&
        ((cm->frame_type == KEY_FRAME) || cpi->refresh_alt_ref_frame ||
         (cpi->refresh_golden_frame && !rc->is_src_frame_alt_ref)))) {
-    rc->last_boosted_qindex = cm->base_qindex;
+    rc->last_boosted_qindex = qindex;
   }
 
   update_buffer_level(cpi, rc->projected_frame_size);
@@ -1131,7 +1147,7 @@
 
   // Actual bits spent
   rc->total_actual_bits += rc->projected_frame_size;
-  rc->total_target_bits += (cm->show_frame ? rc->av_per_frame_bandwidth : 0);
+  rc->total_target_bits += cm->show_frame ? rc->avg_frame_bandwidth : 0;
 
   rc->total_target_vs_actual = rc->total_actual_bits - rc->total_target_bits;
 
@@ -1173,12 +1189,12 @@
 #if USE_ALTREF_FOR_ONE_PASS
   target = (!rc->is_src_frame_alt_ref &&
             (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) ?
-      (rc->av_per_frame_bandwidth * rc->baseline_gf_interval * af_ratio) /
+      (rc->avg_frame_bandwidth * rc->baseline_gf_interval * af_ratio) /
       (rc->baseline_gf_interval + af_ratio - 1) :
-      (rc->av_per_frame_bandwidth * rc->baseline_gf_interval) /
+      (rc->avg_frame_bandwidth * rc->baseline_gf_interval) /
       (rc->baseline_gf_interval + af_ratio - 1);
 #else
-  target = rc->av_per_frame_bandwidth;
+  target = rc->avg_frame_bandwidth;
 #endif
   return vp9_rc_clamp_pframe_target_size(cpi, target);
 }
@@ -1186,7 +1202,7 @@
 static int calc_iframe_target_size_one_pass_vbr(const VP9_COMP *const cpi) {
   static const int kf_ratio = 25;
   const RATE_CONTROL *rc = &cpi->rc;
-  int target = rc->av_per_frame_bandwidth * kf_ratio;
+  const int target = rc->avg_frame_bandwidth * kf_ratio;
   return vp9_rc_clamp_iframe_target_size(cpi, target);
 }
 
@@ -1196,13 +1212,13 @@
   int target;
   if (!cpi->refresh_alt_ref_frame &&
       (cm->current_video_frame == 0 ||
-       (cm->frame_flags & FRAMEFLAGS_KEY) ||
+       (cpi->frame_flags & FRAMEFLAGS_KEY) ||
        rc->frames_to_key == 0 ||
        (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
     cm->frame_type = KEY_FRAME;
     rc->this_key_frame_forced = cm->current_video_frame != 0 &&
                                 rc->frames_to_key == 0;
-    rc->frames_to_key = cpi->key_frame_frequency;
+    rc->frames_to_key = cpi->oxcf.key_freq;
     rc->kf_boost = DEFAULT_KF_BOOST;
     rc->source_alt_ref_active = 0;
   } else {
@@ -1226,17 +1242,16 @@
 }
 
 static int calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
-  const VP9_CONFIG *oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
   const RATE_CONTROL *rc = &cpi->rc;
   const SVC *const svc = &cpi->svc;
   const int64_t diff = oxcf->optimal_buffer_level - rc->buffer_level;
   const int64_t one_pct_bits = 1 + oxcf->optimal_buffer_level / 100;
-  int min_frame_target = MAX(rc->av_per_frame_bandwidth >> 4,
-                             FRAME_OVERHEAD_BITS);
-  int target = rc->av_per_frame_bandwidth;
+  int min_frame_target = MAX(rc->avg_frame_bandwidth >> 4, FRAME_OVERHEAD_BITS);
+  int target = rc->avg_frame_bandwidth;
   if (svc->number_temporal_layers > 1 &&
-      oxcf->end_usage == USAGE_STREAM_FROM_SERVER) {
-    // Note that for layers, av_per_frame_bandwidth is the cumulative
+      oxcf->rc_mode == RC_MODE_CBR) {
+    // Note that for layers, avg_frame_bandwidth is the cumulative
     // per-frame-bandwidth. For the target size of this frame, use the
     // layer average frame size (i.e., non-cumulative per-frame-bw).
     int current_temporal_layer = svc->temporal_layer_id;
@@ -1258,19 +1273,27 @@
 
 static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
   const RATE_CONTROL *rc = &cpi->rc;
+  const VP9EncoderConfig *oxcf = &cpi->oxcf;
+  const SVC *const svc = &cpi->svc;
   int target;
-
   if (cpi->common.current_video_frame == 0) {
     target = ((cpi->oxcf.starting_buffer_level / 2) > INT_MAX)
       ? INT_MAX : (int)(cpi->oxcf.starting_buffer_level / 2);
   } else {
-    const int initial_boost = 32;
-    int kf_boost = MAX(initial_boost, (int)(2 * cpi->output_framerate - 16));
-    if (rc->frames_since_key < cpi->output_framerate / 2) {
-      kf_boost = (int)(kf_boost * rc->frames_since_key /
-                       (cpi->output_framerate / 2));
+    int kf_boost = 32;
+    double framerate = oxcf->framerate;
+    if (svc->number_temporal_layers > 1 &&
+        oxcf->rc_mode == RC_MODE_CBR) {
+      // Use the layer framerate for temporal layers CBR mode.
+      const LAYER_CONTEXT *lc = &svc->layer_context[svc->temporal_layer_id];
+      framerate = lc->framerate;
     }
-    target = ((16 + kf_boost) * rc->av_per_frame_bandwidth) >> 4;
+    kf_boost = MAX(kf_boost, (int)(2 * framerate - 16));
+    if (rc->frames_since_key <  framerate / 2) {
+      kf_boost = (int)(kf_boost * rc->frames_since_key /
+                       (framerate / 2));
+    }
+    target = ((16 + kf_boost) * rc->avg_frame_bandwidth) >> 4;
   }
   return vp9_rc_clamp_iframe_target_size(cpi, target);
 }
@@ -1278,19 +1301,19 @@
 void vp9_rc_get_svc_params(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
-  int target = rc->av_per_frame_bandwidth;
+  int target = rc->avg_frame_bandwidth;
   if ((cm->current_video_frame == 0) ||
-      (cm->frame_flags & FRAMEFLAGS_KEY) ||
+      (cpi->frame_flags & FRAMEFLAGS_KEY) ||
       (cpi->oxcf.auto_key && (rc->frames_since_key %
-                              cpi->key_frame_frequency == 0))) {
+          cpi->oxcf.key_freq == 0))) {
     cm->frame_type = KEY_FRAME;
     rc->source_alt_ref_active = 0;
-    if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+    if (cpi->pass == 0 && cpi->oxcf.rc_mode == RC_MODE_CBR) {
       target = calc_iframe_target_size_one_pass_cbr(cpi);
     }
   } else {
     cm->frame_type = INTER_FRAME;
-    if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+    if (cpi->pass == 0 && cpi->oxcf.rc_mode == RC_MODE_CBR) {
       target = calc_pframe_target_size_one_pass_cbr(cpi);
     }
   }
@@ -1304,13 +1327,13 @@
   RATE_CONTROL *const rc = &cpi->rc;
   int target;
   if ((cm->current_video_frame == 0 ||
-      (cm->frame_flags & FRAMEFLAGS_KEY) ||
+      (cpi->frame_flags & FRAMEFLAGS_KEY) ||
       rc->frames_to_key == 0 ||
       (cpi->oxcf.auto_key && test_for_kf_one_pass(cpi)))) {
     cm->frame_type = KEY_FRAME;
     rc->this_key_frame_forced = cm->current_video_frame != 0 &&
                                 rc->frames_to_key == 0;
-    rc->frames_to_key = cpi->key_frame_frequency;
+    rc->frames_to_key = cpi->oxcf.key_freq;
     rc->kf_boost = DEFAULT_KF_BOOST;
     rc->source_alt_ref_active = 0;
     target = calc_iframe_target_size_one_pass_cbr(cpi);
@@ -1366,3 +1389,46 @@
 
   return target_index - qindex;
 }
+
+void vp9_rc_update_framerate(VP9_COMP *cpi) {
+  const VP9_COMMON *const cm = &cpi->common;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
+  RATE_CONTROL *const rc = &cpi->rc;
+  int vbr_max_bits;
+
+  rc->avg_frame_bandwidth = (int)(oxcf->target_bandwidth / oxcf->framerate);
+  rc->min_frame_bandwidth = (int)(rc->avg_frame_bandwidth *
+                                oxcf->two_pass_vbrmin_section / 100);
+
+  rc->min_frame_bandwidth = MAX(rc->min_frame_bandwidth, FRAME_OVERHEAD_BITS);
+
+  // A maximum bitrate for a frame is defined.
+  // The baseline for this aligns with HW implementations that
+  // can support decode of 1080P content up to a bitrate of MAX_MB_RATE bits
+  // per 16x16 MB (averaged over a frame). However this limit is extended if
+  // a very high rate is given on the command line or the the rate cannnot
+  // be acheived because of a user specificed max q (e.g. when the user
+  // specifies lossless encode.
+  vbr_max_bits = (int)(((int64_t)rc->avg_frame_bandwidth *
+                     oxcf->two_pass_vbrmax_section) / 100);
+  rc->max_frame_bandwidth = MAX(MAX((cm->MBs * MAX_MB_RATE), MAXRATE_1080P),
+                                    vbr_max_bits);
+
+  // Set Maximum gf/arf interval
+  rc->max_gf_interval = 16;
+
+  // Extended interval for genuinely static scenes
+  rc->static_scene_max_gf_interval = cpi->oxcf.key_freq >> 1;
+
+  // Special conditions when alt ref frame enabled in lagged compress mode
+  if (oxcf->play_alternate && oxcf->lag_in_frames) {
+    if (rc->max_gf_interval > oxcf->lag_in_frames - 1)
+      rc->max_gf_interval = oxcf->lag_in_frames - 1;
+
+    if (rc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
+      rc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
+  }
+
+  if (rc->max_gf_interval > rc->static_scene_max_gf_interval)
+    rc->max_gf_interval = rc->static_scene_max_gf_interval;
+}
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index 7693c2b..b1cc676 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -20,14 +20,14 @@
 extern "C" {
 #endif
 
-#define FRAME_OVERHEAD_BITS 200
-
 // Bits Per MB at different Q (Multiplied by 512)
 #define BPER_MB_NORMBITS    9
 
 typedef struct {
   // Rate targetting variables
-  int this_frame_target;
+  int base_frame_target;           // A baseline frame target before adjustment
+                                   // for previous under or over shoot.
+  int this_frame_target;           // Actual frame target after rc adjustment.
   int projected_frame_size;
   int sb64_target_rate;
   int last_q[3];                   // Separate values for Intra/Inter/ARF-GF
@@ -54,9 +54,9 @@
   int source_alt_ref_active;
   int is_src_frame_alt_ref;
 
-  int av_per_frame_bandwidth;     // Average frame size target for clip
-  int min_frame_bandwidth;        // Minimum allocation used for any frame
-  int max_frame_bandwidth;        // Maximum burst rate allowed for a frame.
+  int avg_frame_bandwidth;  // Average frame size target for clip
+  int min_frame_bandwidth;  // Minimum allocation used for any frame
+  int max_frame_bandwidth;  // Maximum burst rate allowed for a frame.
 
   int ni_av_qi;
   int ni_tot_qi;
@@ -67,6 +67,7 @@
 
   int64_t buffer_level;
   int64_t bits_off_target;
+  int64_t vbr_bits_off_target;
 
   int decimation_factor;
   int decimation_count;
@@ -87,9 +88,10 @@
 } RATE_CONTROL;
 
 struct VP9_COMP;
-struct VP9_CONFIG;
+struct VP9EncoderConfig;
 
-void vp9_rc_init(const struct VP9_CONFIG *oxcf, int pass, RATE_CONTROL *rc);
+void vp9_rc_init(const struct VP9EncoderConfig *oxcf, int pass,
+                 RATE_CONTROL *rc);
 
 double vp9_convert_qindex_to_q(int qindex);
 
@@ -125,8 +127,7 @@
 
 // Post encode update of the rate control parameters based
 // on bytes used
-void vp9_rc_postencode_update(struct VP9_COMP *cpi,
-                              uint64_t bytes_used);
+void vp9_rc_postencode_update(struct VP9_COMP *cpi, uint64_t bytes_used);
 // Post encode update of the rate control parameters for dropped frames
 void vp9_rc_postencode_update_drop_frame(struct VP9_COMP *cpi);
 
@@ -175,6 +176,8 @@
 int vp9_compute_qdelta_by_rate(const RATE_CONTROL *rc, FRAME_TYPE frame_type,
                                int qindex, double rate_target_ratio);
 
+void vp9_rc_update_framerate(struct VP9_COMP *cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 1b4cc51..f854356 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -33,8 +33,8 @@
 #include "vp9/encoder/vp9_cost.h"
 #include "vp9/encoder/vp9_encodemb.h"
 #include "vp9/encoder/vp9_encodemv.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_mcomp.h"
-#include "vp9/encoder/vp9_onyx_int.h"
 #include "vp9/encoder/vp9_quantize.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 #include "vp9/encoder/vp9_rdopt.h"
@@ -56,7 +56,7 @@
 #define MIN_EARLY_TERM_INDEX    3
 
 typedef struct {
-  MB_PREDICTION_MODE mode;
+  PREDICTION_MODE mode;
   MV_REFERENCE_FRAME ref_frame[2];
 } MODE_DEFINITION;
 
@@ -243,8 +243,7 @@
   cpi->mb.sadperbit4 = sad_per_bit4lut[qindex];
 }
 
-static void set_block_thresholds(VP9_COMP *cpi) {
-  const VP9_COMMON *const cm = &cpi->common;
+static void set_block_thresholds(const VP9_COMMON *cm, RD_OPT *rd) {
   int i, bsize, segment_id;
 
   for (segment_id = 0; segment_id < MAX_SEGMENTS; ++segment_id) {
@@ -259,16 +258,18 @@
       const int t = q * rd_thresh_block_size_factor[bsize];
       const int thresh_max = INT_MAX / t;
 
-      for (i = 0; i < MAX_MODES; ++i)
-        cpi->rd_threshes[segment_id][bsize][i] =
-            cpi->rd_thresh_mult[i] < thresh_max ? cpi->rd_thresh_mult[i] * t / 4
-                                            : INT_MAX;
-
-      for (i = 0; i < MAX_REFS; ++i) {
-        cpi->rd_thresh_sub8x8[segment_id][bsize][i] =
-            cpi->rd_thresh_mult_sub8x8[i] < thresh_max
-                ? cpi->rd_thresh_mult_sub8x8[i] * t / 4
-                : INT_MAX;
+      if (bsize >= BLOCK_8X8) {
+        for (i = 0; i < MAX_MODES; ++i)
+          rd->threshes[segment_id][bsize][i] =
+              rd->thresh_mult[i] < thresh_max
+                  ? rd->thresh_mult[i] * t / 4
+                  : INT_MAX;
+      } else {
+        for (i = 0; i < MAX_REFS; ++i)
+          rd->threshes[segment_id][bsize][i] =
+              rd->thresh_mult_sub8x8[i] < thresh_max
+                  ? rd->thresh_mult_sub8x8[i] * t / 4
+                  : INT_MAX;
       }
     }
   }
@@ -277,20 +278,21 @@
 void vp9_initialize_rd_consts(VP9_COMP *cpi) {
   VP9_COMMON *const cm = &cpi->common;
   MACROBLOCK *const x = &cpi->mb;
+  RD_OPT *const rd = &cpi->rd;
   int i;
 
   vp9_clear_system_state();
 
-  cpi->RDDIV = RDDIV_BITS;  // in bits (to multiply D by 128)
-  cpi->RDMULT = vp9_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q);
+  rd->RDDIV = RDDIV_BITS;  // in bits (to multiply D by 128)
+  rd->RDMULT = vp9_compute_rd_mult(cpi, cm->base_qindex + cm->y_dc_delta_q);
 
-  x->errorperbit = cpi->RDMULT / RD_MULT_EPB_RATIO;
+  x->errorperbit = rd->RDMULT / RD_MULT_EPB_RATIO;
   x->errorperbit += (x->errorperbit == 0);
 
   x->select_txfm_size = (cpi->sf.tx_size_search_method == USE_LARGESTALL &&
                          cm->frame_type != KEY_FRAME) ? 0 : 1;
 
-  set_block_thresholds(cpi);
+  set_block_thresholds(cm, rd);
 
   if (!cpi->sf.use_nonrd_pick_mode || cm->frame_type == KEY_FRAME) {
     fill_token_costs(x->token_costs, cm->fc.coef_probs);
@@ -448,7 +450,7 @@
       x->pred_sse[ref] = sse;
 
     // Fast approximate the modelling function.
-    if (cpi->speed > 4) {
+    if (cpi->oxcf.speed > 4) {
       int64_t rate;
       int64_t dist;
       int64_t square_error = sse;
@@ -1019,8 +1021,8 @@
 }
 
 
-static int conditional_skipintra(MB_PREDICTION_MODE mode,
-                                 MB_PREDICTION_MODE best_intra_mode) {
+static int conditional_skipintra(PREDICTION_MODE mode,
+                                 PREDICTION_MODE best_intra_mode) {
   if (mode == D117_PRED &&
       best_intra_mode != V_PRED &&
       best_intra_mode != D135_PRED)
@@ -1041,13 +1043,13 @@
 }
 
 static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int ib,
-                                     MB_PREDICTION_MODE *best_mode,
+                                     PREDICTION_MODE *best_mode,
                                      const int *bmode_costs,
                                      ENTROPY_CONTEXT *a, ENTROPY_CONTEXT *l,
                                      int *bestrate, int *bestratey,
                                      int64_t *bestdistortion,
                                      BLOCK_SIZE bsize, int64_t rd_thresh) {
-  MB_PREDICTION_MODE mode;
+  PREDICTION_MODE mode;
   MACROBLOCKD *const xd = &x->e_mbd;
   int64_t best_rd = rd_thresh;
 
@@ -1193,13 +1195,13 @@
   // Pick modes for each sub-block (of size 4x4, 4x8, or 8x4) in an 8x8 block.
   for (idy = 0; idy < 2; idy += num_4x4_blocks_high) {
     for (idx = 0; idx < 2; idx += num_4x4_blocks_wide) {
-      MB_PREDICTION_MODE best_mode = DC_PRED;
+      PREDICTION_MODE best_mode = DC_PRED;
       int r = INT_MAX, ry = INT_MAX;
       int64_t d = INT64_MAX, this_rd = INT64_MAX;
       i = idy * 2 + idx;
       if (cpi->common.frame_type == KEY_FRAME) {
-        const MB_PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, i);
-        const MB_PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, i);
+        const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, i);
+        const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, i);
 
         bmode_costs  = mb->y_mode_costs[A][L];
       }
@@ -1240,8 +1242,8 @@
                                       BLOCK_SIZE bsize,
                                       int64_t tx_cache[TX_MODES],
                                       int64_t best_rd) {
-  MB_PREDICTION_MODE mode;
-  MB_PREDICTION_MODE mode_selected = DC_PRED;
+  PREDICTION_MODE mode;
+  PREDICTION_MODE mode_selected = DC_PRED;
   MACROBLOCKD *const xd = &x->e_mbd;
   MODE_INFO *const mic = xd->mi[0];
   int this_rate, this_rate_tokenonly, s;
@@ -1264,8 +1266,8 @@
       continue;
 
     if (cpi->common.frame_type == KEY_FRAME) {
-      const MB_PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0);
-      const MB_PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0);
+      const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0);
+      const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0);
 
       bmode_costs = x->y_mode_costs[A][L];
     }
@@ -1359,8 +1361,8 @@
                                        int64_t *distortion, int *skippable,
                                        BLOCK_SIZE bsize, TX_SIZE max_tx_size) {
   MACROBLOCKD *xd = &x->e_mbd;
-  MB_PREDICTION_MODE mode;
-  MB_PREDICTION_MODE mode_selected = DC_PRED;
+  PREDICTION_MODE mode;
+  PREDICTION_MODE mode_selected = DC_PRED;
   int64_t best_rd = INT64_MAX, this_rd;
   int this_rate_tokenonly, this_rate, s;
   int64_t this_distortion, this_sse;
@@ -1432,7 +1434,7 @@
                                  BLOCK_SIZE bsize, TX_SIZE max_tx_size,
                                  int *rate_uv, int *rate_uv_tokenonly,
                                  int64_t *dist_uv, int *skip_uv,
-                                 MB_PREDICTION_MODE *mode_uv) {
+                                 PREDICTION_MODE *mode_uv) {
   MACROBLOCK *const x = &cpi->mb;
 
   // Use an estimated rd for uv_intra based on DC_PRED if the
@@ -1450,7 +1452,7 @@
   *mode_uv = x->e_mbd.mi[0]->mbmi.uv_mode;
 }
 
-static int cost_mv_ref(const VP9_COMP *cpi, MB_PREDICTION_MODE mode,
+static int cost_mv_ref(const VP9_COMP *cpi, PREDICTION_MODE mode,
                        int mode_context) {
   const MACROBLOCK *const x = &cpi->mb;
   const int segment_id = x->e_mbd.mi[0]->mbmi.segment_id;
@@ -1471,13 +1473,12 @@
                                 int_mv single_newmv[MAX_REF_FRAMES],
                                 int *rate_mv);
 
-static int labels2mode(VP9_COMP *cpi, MACROBLOCKD *xd, int i,
-                       MB_PREDICTION_MODE mode,
-                       int_mv this_mv[2],
-                       int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES],
-                       int_mv seg_mvs[MAX_REF_FRAMES],
-                       int_mv *best_ref_mv[2],
-                       const int *mvjcost, int *mvcost[2]) {
+static int set_and_cost_bmi_mvs(VP9_COMP *cpi, MACROBLOCKD *xd, int i,
+                                PREDICTION_MODE mode, int_mv this_mv[2],
+                                int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES],
+                                int_mv seg_mvs[MAX_REF_FRAMES],
+                                int_mv *best_ref_mv[2], const int *mvjcost,
+                                int *mvcost[2]) {
   MODE_INFO *const mic = xd->mi[0];
   const MB_MODE_INFO *const mbmi = &mic->mbmi;
   int thismvcost = 0;
@@ -1486,8 +1487,6 @@
   const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[mbmi->sb_type];
   const int is_compound = has_second_ref(mbmi);
 
-  // the only time we should do costing for new motion vector or mode
-  // is when we are on a new label  (jbb May 08, 2007)
   switch (mode) {
     case NEWMV:
       this_mv[0].as_int = seg_mvs[mbmi->ref_frame[0]].as_int;
@@ -1499,15 +1498,11 @@
                                       mvjcost, mvcost, MV_COST_WEIGHT_SUB);
       }
       break;
-    case NEARESTMV:
-      this_mv[0].as_int = frame_mv[NEARESTMV][mbmi->ref_frame[0]].as_int;
-      if (is_compound)
-        this_mv[1].as_int = frame_mv[NEARESTMV][mbmi->ref_frame[1]].as_int;
-      break;
     case NEARMV:
-      this_mv[0].as_int = frame_mv[NEARMV][mbmi->ref_frame[0]].as_int;
+    case NEARESTMV:
+      this_mv[0].as_int = frame_mv[mode][mbmi->ref_frame[0]].as_int;
       if (is_compound)
-        this_mv[1].as_int = frame_mv[NEARMV][mbmi->ref_frame[1]].as_int;
+        this_mv[1].as_int = frame_mv[mode][mbmi->ref_frame[1]].as_int;
       break;
     case ZEROMV:
       this_mv[0].as_int = 0;
@@ -1632,7 +1627,7 @@
   int64_t d;
   int64_t sse;
   int segment_yrate;
-  MB_PREDICTION_MODE modes[4];
+  PREDICTION_MODE modes[4];
   SEG_RDSTAT rdstat[4][INTER_MODES];
   int mvthresh;
 } BEST_SEG_INFO;
@@ -1676,14 +1671,14 @@
 static int check_best_zero_mv(
     const VP9_COMP *cpi, const uint8_t mode_context[MAX_REF_FRAMES],
     int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES],
-    int disable_inter_mode_mask, int this_mode, int ref_frame,
-    int second_ref_frame) {
+    int disable_inter_mode_mask, int this_mode,
+    const MV_REFERENCE_FRAME ref_frames[2]) {
   if (!(disable_inter_mode_mask & (1 << INTER_OFFSET(ZEROMV))) &&
       (this_mode == NEARMV || this_mode == NEARESTMV || this_mode == ZEROMV) &&
-      frame_mv[this_mode][ref_frame].as_int == 0 &&
-      (second_ref_frame == NONE ||
-       frame_mv[this_mode][second_ref_frame].as_int == 0)) {
-    int rfc = mode_context[ref_frame];
+      frame_mv[this_mode][ref_frames[0]].as_int == 0 &&
+      (ref_frames[1] == NONE ||
+       frame_mv[this_mode][ref_frames[1]].as_int == 0)) {
+    int rfc = mode_context[ref_frames[0]];
     int c1 = cost_mv_ref(cpi, NEARMV, rfc);
     int c2 = cost_mv_ref(cpi, NEARESTMV, rfc);
     int c3 = cost_mv_ref(cpi, ZEROMV, rfc);
@@ -1694,15 +1689,15 @@
       if (c2 > c3) return 0;
     } else {
       assert(this_mode == ZEROMV);
-      if (second_ref_frame == NONE) {
-        if ((c3 >= c2 && frame_mv[NEARESTMV][ref_frame].as_int == 0) ||
-            (c3 >= c1 && frame_mv[NEARMV][ref_frame].as_int == 0))
+      if (ref_frames[1] == NONE) {
+        if ((c3 >= c2 && frame_mv[NEARESTMV][ref_frames[0]].as_int == 0) ||
+            (c3 >= c1 && frame_mv[NEARMV][ref_frames[0]].as_int == 0))
           return 0;
       } else {
-        if ((c3 >= c2 && frame_mv[NEARESTMV][ref_frame].as_int == 0 &&
-             frame_mv[NEARESTMV][second_ref_frame].as_int == 0) ||
-            (c3 >= c1 && frame_mv[NEARMV][ref_frame].as_int == 0 &&
-             frame_mv[NEARMV][second_ref_frame].as_int == 0))
+        if ((c3 >= c2 && frame_mv[NEARESTMV][ref_frames[0]].as_int == 0 &&
+             frame_mv[NEARESTMV][ref_frames[1]].as_int == 0) ||
+            (c3 >= c1 && frame_mv[NEARMV][ref_frames[0]].as_int == 0 &&
+             frame_mv[NEARMV][ref_frames[1]].as_int == 0))
           return 0;
       }
     }
@@ -1710,18 +1705,28 @@
   return 1;
 }
 
-static void rd_check_segment_txsize(VP9_COMP *cpi, MACROBLOCK *x,
-                                    const TileInfo *const tile,
-                                    BEST_SEG_INFO *bsi_buf, int filter_idx,
-                                    int_mv seg_mvs[4][MAX_REF_FRAMES],
-                                    int mi_row, int mi_col) {
+static int64_t rd_pick_best_sub8x8_mode(VP9_COMP *cpi, MACROBLOCK *x,
+                                        const TileInfo * const tile,
+                                        int_mv *best_ref_mv,
+                                        int_mv *second_best_ref_mv,
+                                        int64_t best_rd, int *returntotrate,
+                                        int *returnyrate,
+                                        int64_t *returndistortion,
+                                        int *skippable, int64_t *psse,
+                                        int mvthresh,
+                                        int_mv seg_mvs[4][MAX_REF_FRAMES],
+                                        BEST_SEG_INFO *bsi_buf, int filter_idx,
+                                        int mi_row, int mi_col) {
+  int i;
+  BEST_SEG_INFO *bsi = bsi_buf + filter_idx;
+  MACROBLOCKD *xd = &x->e_mbd;
+  MODE_INFO *mi = xd->mi[0];
+  MB_MODE_INFO *mbmi = &mi->mbmi;
+  int mode_idx;
   int k, br = 0, idx, idy;
   int64_t bd = 0, block_sse = 0;
-  MB_PREDICTION_MODE this_mode;
-  MACROBLOCKD *xd = &x->e_mbd;
+  PREDICTION_MODE this_mode;
   VP9_COMMON *cm = &cpi->common;
-  MODE_INFO *mi = xd->mi[0];
-  MB_MODE_INFO *const mbmi = &mi->mbmi;
   struct macroblock_plane *const p = &x->plane[0];
   struct macroblockd_plane *const pd = &xd->plane[0];
   const int label_count = 4;
@@ -1733,12 +1738,21 @@
   const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize];
   vp9_variance_fn_ptr_t *v_fn_ptr = &cpi->fn_ptr[bsize];
   ENTROPY_CONTEXT t_above[2], t_left[2];
-  BEST_SEG_INFO *bsi = bsi_buf + filter_idx;
-  int mode_idx;
   int subpelmv = 1, have_ref = 0;
   const int has_second_rf = has_second_ref(mbmi);
   const int disable_inter_mode_mask = cpi->sf.disable_inter_mode_mask[bsize];
 
+  vp9_zero(*bsi);
+
+  bsi->segment_rd = best_rd;
+  bsi->ref_mv[0] = best_ref_mv;
+  bsi->ref_mv[1] = second_best_ref_mv;
+  bsi->mvp.as_int = best_ref_mv->as_int;
+  bsi->mvthresh = mvthresh;
+
+  for (i = 0; i < 4; i++)
+    bsi->modes[i] = ZEROMV;
+
   vpx_memcpy(t_above, pd->above_context, sizeof(t_above));
   vpx_memcpy(t_left, pd->left_context, sizeof(t_left));
 
@@ -1755,7 +1769,7 @@
       // loop for 4x4/4x8/8x4 block coding. to be replaced with new rd loop
       int_mv mode_mv[MB_MODE_COUNT][2];
       int_mv frame_mv[MB_MODE_COUNT][MAX_REF_FRAMES];
-      MB_PREDICTION_MODE mode_selected = ZEROMV;
+      PREDICTION_MODE mode_selected = ZEROMV;
       int64_t best_rd = INT64_MAX;
       const int i = idy * 2 + idx;
       int ref;
@@ -1780,8 +1794,7 @@
 
         if (!check_best_zero_mv(cpi, mbmi->mode_context, frame_mv,
                                 disable_inter_mode_mask,
-                                this_mode, mbmi->ref_frame[0],
-                                mbmi->ref_frame[1]))
+                                this_mode, mbmi->ref_frame))
           continue;
 
         vpx_memcpy(orig_pre, pd->pre, sizeof(orig_pre));
@@ -1793,7 +1806,7 @@
         // motion search for newmv (single predictor case only)
         if (!has_second_rf && this_mode == NEWMV &&
             seg_mvs[i][mbmi->ref_frame[0]].as_int == INVALID_MV) {
-          int_mv *const new_mv = &mode_mv[NEWMV][0];
+          MV *const new_mv = &mode_mv[NEWMV][0].as_mv;
           int step_param = 0;
           int further_steps;
           int thissme, bestsme = INT_MAX;
@@ -1806,8 +1819,7 @@
           if (best_rd < label_mv_thresh)
             break;
 
-          if (cpi->oxcf.mode != MODE_SECONDPASS_BEST &&
-              cpi->oxcf.mode != MODE_BESTQUALITY) {
+          if (!is_best_mode(cpi->oxcf.mode)) {
             // use previous block's result as next block's MV predictor.
             if (i > 0) {
               bsi->mvp.as_int = mi->bmi[i - 1].as_mv[0].as_int;
@@ -1850,9 +1862,9 @@
                                      step_param,
                                      sadpb, 1, v_fn_ptr, 1,
                                      &bsi->ref_mv[0]->as_mv,
-                                     &new_mv->as_mv);
+                                     new_mv);
             if (bestsme < INT_MAX)
-              bestsme = vp9_get_mvpred_var(x, &new_mv->as_mv,
+              bestsme = vp9_get_mvpred_var(x, new_mv,
                                            &bsi->ref_mv[0]->as_mv,
                                            v_fn_ptr, 1);
           } else if (cpi->sf.search_method == SQUARE) {
@@ -1860,9 +1872,9 @@
                                         step_param,
                                         sadpb, 1, v_fn_ptr, 1,
                                         &bsi->ref_mv[0]->as_mv,
-                                        &new_mv->as_mv);
+                                        new_mv);
             if (bestsme < INT_MAX)
-              bestsme = vp9_get_mvpred_var(x, &new_mv->as_mv,
+              bestsme = vp9_get_mvpred_var(x, new_mv,
                                            &bsi->ref_mv[0]->as_mv,
                                            v_fn_ptr, 1);
           } else if (cpi->sf.search_method == BIGDIA) {
@@ -1870,44 +1882,42 @@
                                         step_param,
                                         sadpb, 1, v_fn_ptr, 1,
                                         &bsi->ref_mv[0]->as_mv,
-                                        &new_mv->as_mv);
+                                        new_mv);
             if (bestsme < INT_MAX)
-              bestsme = vp9_get_mvpred_var(x, &new_mv->as_mv,
+              bestsme = vp9_get_mvpred_var(x, new_mv,
                                            &bsi->ref_mv[0]->as_mv,
                                            v_fn_ptr, 1);
           } else {
             bestsme = vp9_full_pixel_diamond(cpi, x, &mvp_full, step_param,
                                              sadpb, further_steps, 0, v_fn_ptr,
                                              &bsi->ref_mv[0]->as_mv,
-                                             &new_mv->as_mv);
+                                             new_mv);
           }
 
           // Should we do a full search (best quality only)
-          if (cpi->oxcf.mode == MODE_BESTQUALITY ||
-              cpi->oxcf.mode == MODE_SECONDPASS_BEST) {
+          if (is_best_mode(cpi->oxcf.mode)) {
             int_mv *const best_mv = &mi->bmi[i].as_mv[0];
             /* Check if mvp_full is within the range. */
             clamp_mv(&mvp_full, x->mv_col_min, x->mv_col_max,
                      x->mv_row_min, x->mv_row_max);
             thissme = cpi->full_search_sad(x, &mvp_full,
                                            sadpb, 16, v_fn_ptr,
-                                           x->nmvjointcost, x->mvcost,
                                            &bsi->ref_mv[0]->as_mv,
                                            &best_mv->as_mv);
             if (thissme < bestsme) {
               bestsme = thissme;
-              new_mv->as_int = best_mv->as_int;
+              *new_mv = best_mv->as_mv;
             } else {
               // The full search result is actually worse so re-instate the
               // previous best vector
-              best_mv->as_int = new_mv->as_int;
+              best_mv->as_mv = *new_mv;
             }
           }
 
           if (bestsme < INT_MAX) {
             int distortion;
             cpi->find_fractional_mv_step(x,
-                                         &new_mv->as_mv,
+                                         new_mv,
                                          &bsi->ref_mv[0]->as_mv,
                                          cm->allow_high_precision_mv,
                                          x->errorperbit, v_fn_ptr,
@@ -1918,11 +1928,11 @@
                                          &x->pred_sse[mbmi->ref_frame[0]]);
 
             // save motion search result for use in compound prediction
-            seg_mvs[i][mbmi->ref_frame[0]].as_int = new_mv->as_int;
+            seg_mvs[i][mbmi->ref_frame[0]].as_mv = *new_mv;
           }
 
           if (cpi->sf.adaptive_motion_search)
-            x->pred_mv[mbmi->ref_frame[0]].as_int = new_mv->as_int;
+            x->pred_mv[mbmi->ref_frame[0]].as_mv = *new_mv;
 
           // restore src pointers
           mi_buf_restore(x, orig_src, orig_pre);
@@ -1953,8 +1963,9 @@
         }
 
         bsi->rdstat[i][mode_idx].brate =
-            labels2mode(cpi, xd, i, this_mode, mode_mv[this_mode], frame_mv,
-                        seg_mvs[i], bsi->ref_mv, x->nmvjointcost, x->mvcost);
+            set_and_cost_bmi_mvs(cpi, xd, i, this_mode, mode_mv[this_mode],
+                                 frame_mv, seg_mvs[i], bsi->ref_mv,
+                                 x->nmvjointcost, x->mvcost);
 
         for (ref = 0; ref < 1 + has_second_rf; ++ref) {
           bsi->rdstat[i][mode_idx].mvs[ref].as_int =
@@ -2043,16 +2054,16 @@
           for (midx = 0; midx < INTER_MODES; ++midx)
             bsi->rdstat[iy][midx].brdcost = INT64_MAX;
         bsi->segment_rd = INT64_MAX;
-        return;
+        return INT64_MAX;;
       }
 
       mode_idx = INTER_OFFSET(mode_selected);
       vpx_memcpy(t_above, bsi->rdstat[i][mode_idx].ta, sizeof(t_above));
       vpx_memcpy(t_left, bsi->rdstat[i][mode_idx].tl, sizeof(t_left));
 
-      labels2mode(cpi, xd, i, mode_selected, mode_mv[mode_selected],
-                  frame_mv, seg_mvs[i], bsi->ref_mv, x->nmvjointcost,
-                  x->mvcost);
+      set_and_cost_bmi_mvs(cpi, xd, i, mode_selected, mode_mv[mode_selected],
+                           frame_mv, seg_mvs[i], bsi->ref_mv, x->nmvjointcost,
+                           x->mvcost);
 
       br += bsi->rdstat[i][mode_idx].brate;
       bd += bsi->rdstat[i][mode_idx].bdist;
@@ -2066,7 +2077,7 @@
           for (midx = 0; midx < INTER_MODES; ++midx)
             bsi->rdstat[iy][midx].brdcost = INT64_MAX;
         bsi->segment_rd = INT64_MAX;
-        return;
+        return INT64_MAX;;
       }
     }
   } /* for each label */
@@ -2080,42 +2091,6 @@
   // update the coding decisions
   for (k = 0; k < 4; ++k)
     bsi->modes[k] = mi->bmi[k].as_mode;
-}
-
-static int64_t rd_pick_best_mbsegmentation(VP9_COMP *cpi, MACROBLOCK *x,
-                                           const TileInfo *const tile,
-                                           int_mv *best_ref_mv,
-                                           int_mv *second_best_ref_mv,
-                                           int64_t best_rd,
-                                           int *returntotrate,
-                                           int *returnyrate,
-                                           int64_t *returndistortion,
-                                           int *skippable, int64_t *psse,
-                                           int mvthresh,
-                                           int_mv seg_mvs[4][MAX_REF_FRAMES],
-                                           BEST_SEG_INFO *bsi_buf,
-                                           int filter_idx,
-                                           int mi_row, int mi_col) {
-  int i;
-  BEST_SEG_INFO *bsi = bsi_buf + filter_idx;
-  MACROBLOCKD *xd = &x->e_mbd;
-  MODE_INFO *mi = xd->mi[0];
-  MB_MODE_INFO *mbmi = &mi->mbmi;
-  int mode_idx;
-
-  vp9_zero(*bsi);
-
-  bsi->segment_rd = best_rd;
-  bsi->ref_mv[0] = best_ref_mv;
-  bsi->ref_mv[1] = second_best_ref_mv;
-  bsi->mvp.as_int = best_ref_mv->as_int;
-  bsi->mvthresh = mvthresh;
-
-  for (i = 0; i < 4; i++)
-    bsi->modes[i] = ZEROMV;
-
-  rd_check_segment_txsize(cpi, x, tile, bsi_buf, filter_idx, seg_mvs,
-                          mi_row, mi_col);
 
   if (bsi->segment_rd > best_rd)
     return INT64_MAX;
@@ -2202,12 +2177,12 @@
   x->pred_mv_sad[ref_frame] = best_sad;
 }
 
-static void estimate_ref_frame_costs(VP9_COMP *cpi, int segment_id,
+static void estimate_ref_frame_costs(const VP9_COMMON *cm,
+                                     const MACROBLOCKD *xd,
+                                     int segment_id,
                                      unsigned int *ref_costs_single,
                                      unsigned int *ref_costs_comp,
                                      vp9_prob *comp_mode_p) {
-  VP9_COMMON *const cm = &cpi->common;
-  MACROBLOCKD *const xd = &cpi->mb.e_mbd;
   int seg_ref_active = vp9_segfeature_active(&cm->seg, segment_id,
                                              SEG_LVL_REF_FRAME);
   if (seg_ref_active) {
@@ -2372,7 +2347,7 @@
                                  int mi_row, int mi_col,
                                  int_mv *tmp_mv, int *rate_mv) {
   MACROBLOCKD *xd = &x->e_mbd;
-  VP9_COMMON *cm = &cpi->common;
+  const VP9_COMMON *cm = &cpi->common;
   MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
   struct buf_2d backup_yv12[MAX_MB_PLANE] = {{0}};
   int bestsme = INT_MAX;
@@ -2410,7 +2385,7 @@
 
   // Work out the size of the first step in the mv step search.
   // 0 here is maximum length first step. 1 is MAX >> 1 etc.
-  if (cpi->sf.auto_mv_step_size && cpi->common.show_frame) {
+  if (cpi->sf.auto_mv_step_size && cm->show_frame) {
     // Take wtd average of the step_params based on the last frame's
     // max mv magnitude and that based on the best ref mvs of the current
     // block for the given reference.
@@ -2421,7 +2396,7 @@
   }
 
   if (cpi->sf.adaptive_motion_search && bsize < BLOCK_64X64 &&
-      cpi->common.show_frame) {
+      cm->show_frame) {
     int boffset = 2 * (b_width_log2(BLOCK_64X64) - MIN(b_height_log2(bsize),
                                                        b_width_log2(bsize)));
     step_param = MAX(step_param, boffset);
@@ -2436,7 +2411,7 @@
     if (tlevel < 5)
       step_param += 2;
 
-    for (i = LAST_FRAME; i <= ALTREF_FRAME && cpi->common.show_frame; ++i) {
+    for (i = LAST_FRAME; i <= ALTREF_FRAME && cm->show_frame; ++i) {
       if ((x->pred_mv_sad[ref] >> 3) > x->pred_mv_sad[i]) {
         x->pred_mv[ref].as_int = 0;
         tmp_mv->as_int = INVALID_MV;
@@ -2520,7 +2495,7 @@
   *rate_mv = vp9_mv_bit_cost(&tmp_mv->as_mv, &ref_mv,
                              x->nmvjointcost, x->mvcost, MV_COST_WEIGHT);
 
-  if (cpi->sf.adaptive_motion_search && cpi->common.show_frame)
+  if (cpi->sf.adaptive_motion_search && cm->show_frame)
     x->pred_mv[ref].as_int = tmp_mv->as_int;
 
   if (scaled_ref_frame) {
@@ -2580,7 +2555,7 @@
     struct buf_2d ref_yv12[2];
     int bestsme = INT_MAX;
     int sadpb = x->sadperbit16;
-    int_mv tmp_mv;
+    MV tmp_mv;
     int search_range = 3;
 
     int tmp_col_min = x->mv_col_min;
@@ -2609,20 +2584,19 @@
     vp9_set_mv_search_range(x, &ref_mv[id].as_mv);
 
     // Use mv result from single mode as mvp.
-    tmp_mv.as_int = frame_mv[refs[id]].as_int;
+    tmp_mv = frame_mv[refs[id]].as_mv;
 
-    tmp_mv.as_mv.col >>= 3;
-    tmp_mv.as_mv.row >>= 3;
+    tmp_mv.col >>= 3;
+    tmp_mv.row >>= 3;
 
     // Small-range full-pixel motion search
-    bestsme = vp9_refining_search_8p_c(x, &tmp_mv.as_mv, sadpb,
+    bestsme = vp9_refining_search_8p_c(x, &tmp_mv, sadpb,
                                        search_range,
                                        &cpi->fn_ptr[bsize],
-                                       x->nmvjointcost, x->mvcost,
                                        &ref_mv[id].as_mv, second_pred,
                                        pw, ph);
     if (bestsme < INT_MAX)
-      bestsme = vp9_get_mvpred_av_var(x, &tmp_mv.as_mv, &ref_mv[id].as_mv,
+      bestsme = vp9_get_mvpred_av_var(x, &tmp_mv, &ref_mv[id].as_mv,
                                       second_pred, &cpi->fn_ptr[bsize], 1);
 
     x->mv_col_min = tmp_col_min;
@@ -2634,7 +2608,7 @@
       int dis; /* TODO: use dis in distortion calculation later. */
       unsigned int sse;
       bestsme = cpi->find_fractional_mv_step_comp(
-          x, &tmp_mv.as_mv,
+          x, &tmp_mv,
           &ref_mv[id].as_mv,
           cpi->common.allow_high_precision_mv,
           x->errorperbit,
@@ -2649,7 +2623,7 @@
       xd->plane[0].pre[0] = scaled_first_yv12;
 
     if (bestsme < last_besterr[id]) {
-      frame_mv[refs[id]].as_int = tmp_mv.as_int;
+      frame_mv[refs[id]].as_mv = tmp_mv;
       last_besterr[id] = bestsme;
     } else {
       break;
@@ -2699,6 +2673,7 @@
                                  int64_t *psse,
                                  const int64_t ref_best_rd) {
   VP9_COMMON *cm = &cpi->common;
+  RD_OPT *rd_opt = &cpi->rd;
   MACROBLOCKD *xd = &x->e_mbd;
   MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
   const int is_comp_pred = has_second_ref(mbmi);
@@ -2796,14 +2771,13 @@
 
   // Search for best switchable filter by checking the variance of
   // pred error irrespective of whether the filter will be used
-  cpi->mask_filter_rd = 0;
+  rd_opt->mask_filter = 0;
   for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
-    cpi->rd_filter_cache[i] = INT64_MAX;
+    rd_opt->filter_cache[i] = INT64_MAX;
 
   if (cm->interp_filter != BILINEAR) {
     *best_filter = EIGHTTAP;
-    if (x->source_variance <
-        cpi->sf.disable_filter_search_var_thresh) {
+    if (x->source_variance < cpi->sf.disable_filter_search_var_thresh) {
       *best_filter = EIGHTTAP;
     } else {
       int newbest;
@@ -2819,12 +2793,12 @@
 
         if (i > 0 && intpel_mv) {
           rd = RDCOST(x->rdmult, x->rddiv, tmp_rate_sum, tmp_dist_sum);
-          cpi->rd_filter_cache[i] = rd;
-          cpi->rd_filter_cache[SWITCHABLE_FILTERS] =
-              MIN(cpi->rd_filter_cache[SWITCHABLE_FILTERS], rd + rs_rd);
+          rd_opt->filter_cache[i] = rd;
+          rd_opt->filter_cache[SWITCHABLE_FILTERS] =
+              MIN(rd_opt->filter_cache[SWITCHABLE_FILTERS], rd + rs_rd);
           if (cm->interp_filter == SWITCHABLE)
             rd += rs_rd;
-          cpi->mask_filter_rd = MAX(cpi->mask_filter_rd, rd);
+          rd_opt->mask_filter = MAX(rd_opt->mask_filter, rd);
         } else {
           int rate_sum = 0;
           int64_t dist_sum = 0;
@@ -2844,12 +2818,12 @@
           model_rd_for_sb(cpi, bsize, x, xd, &rate_sum, &dist_sum);
 
           rd = RDCOST(x->rdmult, x->rddiv, rate_sum, dist_sum);
-          cpi->rd_filter_cache[i] = rd;
-          cpi->rd_filter_cache[SWITCHABLE_FILTERS] =
-              MIN(cpi->rd_filter_cache[SWITCHABLE_FILTERS], rd + rs_rd);
+          rd_opt->filter_cache[i] = rd;
+          rd_opt->filter_cache[SWITCHABLE_FILTERS] =
+              MIN(rd_opt->filter_cache[SWITCHABLE_FILTERS], rd + rs_rd);
           if (cm->interp_filter == SWITCHABLE)
             rd += rs_rd;
-          cpi->mask_filter_rd = MAX(cpi->mask_filter_rd, rd);
+          rd_opt->mask_filter = MAX(rd_opt->mask_filter, rd);
 
           if (i == 0 && intpel_mv) {
             tmp_rate_sum = rate_sum;
@@ -3117,6 +3091,34 @@
   ctx->mic = *xd->mi[0];
 }
 
+static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh,
+                                      int thresh_fact) {
+    return best_rd < ((int64_t)thresh * thresh_fact >> 5) || thresh == INT_MAX;
+}
+
+// Updating rd_thresh_freq_fact[] here means that the different
+// partition/block sizes are handled independently based on the best
+// choice for the current partition. It may well be better to keep a scaled
+// best rd so far value and update rd_thresh_freq_fact based on the mode/size
+// combination that wins out.
+static void update_rd_thresh_fact(VP9_COMP *cpi, int bsize,
+                                  int best_mode_index) {
+  if (cpi->sf.adaptive_rd_thresh > 0) {
+    const int top_mode = bsize < BLOCK_8X8 ? MAX_REFS : MAX_MODES;
+    int mode;
+    for (mode = 0; mode < top_mode; ++mode) {
+      int *const fact = &cpi->rd.thresh_freq_fact[bsize][mode];
+
+      if (mode == best_mode_index) {
+        *fact -= (*fact >> 3);
+      } else {
+        *fact = MIN(*fact + RD_THRESH_INC,
+                    cpi->sf.adaptive_rd_thresh * RD_THRESH_MAX_FACT);
+      }
+    }
+  }
+}
+
 int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
                                   const TileInfo *const tile,
                                   int mi_row, int mi_col,
@@ -3126,10 +3128,11 @@
                                   PICK_MODE_CONTEXT *ctx,
                                   int64_t best_rd_so_far) {
   VP9_COMMON *const cm = &cpi->common;
+  RD_OPT *const rd_opt = &cpi->rd;
   MACROBLOCKD *const xd = &x->e_mbd;
   MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
   const struct segmentation *const seg = &cm->seg;
-  MB_PREDICTION_MODE this_mode;
+  PREDICTION_MODE this_mode;
   MV_REFERENCE_FRAME ref_frame, second_ref_frame;
   unsigned char segment_id = mbmi->segment_id;
   int comp_pred, i;
@@ -3151,13 +3154,13 @@
   vp9_prob comp_mode_p;
   int64_t best_intra_rd = INT64_MAX;
   int64_t best_inter_rd = INT64_MAX;
-  MB_PREDICTION_MODE best_intra_mode = DC_PRED;
+  PREDICTION_MODE best_intra_mode = DC_PRED;
   MV_REFERENCE_FRAME best_inter_ref_frame = LAST_FRAME;
   INTERP_FILTER tmp_best_filter = SWITCHABLE;
   int rate_uv_intra[TX_SIZES], rate_uv_tokenonly[TX_SIZES];
   int64_t dist_uv[TX_SIZES];
   int skip_uv[TX_SIZES];
-  MB_PREDICTION_MODE mode_uv[TX_SIZES];
+  PREDICTION_MODE mode_uv[TX_SIZES];
   int64_t mode_distortions[MB_MODE_COUNT] = {-1};
   int intra_cost_penalty = 20 * vp9_dc_quant(cm->base_qindex, cm->y_dc_delta_q);
   const int bws = num_8x8_blocks_wide_lookup[bsize] / 2;
@@ -3165,8 +3168,8 @@
   int best_skip2 = 0;
   int mode_skip_mask = 0;
   int mode_skip_start = cpi->sf.mode_skip_start + 1;
-  const int *const rd_threshes = cpi->rd_threshes[segment_id][bsize];
-  const int *const rd_thresh_freq_fact = cpi->rd_thresh_freq_fact[bsize];
+  const int *const rd_threshes = rd_opt->threshes[segment_id][bsize];
+  const int *const rd_thresh_freq_fact = rd_opt->thresh_freq_fact[bsize];
   const int mode_search_skip_flags = cpi->sf.mode_search_skip_flags;
   const int intra_y_mode_mask =
       cpi->sf.intra_y_mode_mask[max_txsize_lookup[bsize]];
@@ -3174,7 +3177,7 @@
 
   x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
 
-  estimate_ref_frame_costs(cpi, segment_id, ref_costs_single, ref_costs_comp,
+  estimate_ref_frame_costs(cm, xd, segment_id, ref_costs_single, ref_costs_comp,
                            &comp_mode_p);
 
   for (i = 0; i < REFERENCE_MODES; ++i)
@@ -3247,9 +3250,8 @@
     // an unfiltered alternative. We allow near/nearest as well
     // because they may result in zero-zero MVs but be cheaper.
     if (cpi->rc.is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) {
-      const int altref_zero_mask =
+      mode_skip_mask =
           ~((1 << THR_NEARESTA) | (1 << THR_NEARA) | (1 << THR_ZEROA));
-      mode_skip_mask |= altref_zero_mask;
       if (frame_mv[NEARMV][ALTREF_FRAME].as_int != 0)
         mode_skip_mask |= (1 << THR_NEARA);
       if (frame_mv[NEARESTMV][ALTREF_FRAME].as_int != 0)
@@ -3325,10 +3327,9 @@
       continue;
 
     // Test best rd so far against threshold for trying this mode.
-    if (best_rd < ((int64_t)rd_threshes[mode_index] *
-                  rd_thresh_freq_fact[mode_index] >> 5) ||
-        rd_threshes[mode_index] == INT_MAX)
-     continue;
+    if (rd_less_than_thresh(best_rd, rd_threshes[mode_index],
+        rd_thresh_freq_fact[mode_index]))
+      continue;
 
     this_mode = vp9_mode_order[mode_index].mode;
     ref_frame = vp9_mode_order[mode_index].ref_frame[0];
@@ -3379,11 +3380,12 @@
       }
     } else {
       if (x->in_active_map &&
-          !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP))
+          !vp9_segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
+        const MV_REFERENCE_FRAME ref_frames[2] = {ref_frame, second_ref_frame};
         if (!check_best_zero_mv(cpi, mbmi->mode_context, frame_mv,
-                                disable_inter_mode_mask, this_mode, ref_frame,
-                                second_ref_frame))
+                                disable_inter_mode_mask, this_mode, ref_frames))
           continue;
+      }
     }
 
     mbmi->mode = this_mode;
@@ -3611,21 +3613,21 @@
 
       /* keep record of best filter type */
       if (!mode_excluded && cm->interp_filter != BILINEAR) {
-        int64_t ref = cpi->rd_filter_cache[cm->interp_filter == SWITCHABLE ?
+        int64_t ref = rd_opt->filter_cache[cm->interp_filter == SWITCHABLE ?
                               SWITCHABLE_FILTERS : cm->interp_filter];
 
         for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
           int64_t adj_rd;
           if (ref == INT64_MAX)
             adj_rd = 0;
-          else if (cpi->rd_filter_cache[i] == INT64_MAX)
+          else if (rd_opt->filter_cache[i] == INT64_MAX)
             // when early termination is triggered, the encoder does not have
             // access to the rate-distortion cost. it only knows that the cost
             // should be above the maximum valid value. hence it takes the known
             // maximum plus an arbitrary constant as the rate-distortion cost.
-            adj_rd = cpi->mask_filter_rd - ref + 10;
+            adj_rd = rd_opt->mask_filter - ref + 10;
           else
-            adj_rd = cpi->rd_filter_cache[i] - ref;
+            adj_rd = rd_opt->filter_cache[i] - ref;
 
           adj_rd += this_rd;
           best_filter_rd[i] = MIN(best_filter_rd[i], adj_rd);
@@ -3680,23 +3682,7 @@
          (cm->interp_filter == best_mbmode.interp_filter) ||
          !is_inter_block(&best_mbmode));
 
-  // Updating rd_thresh_freq_fact[] here means that the different
-  // partition/block sizes are handled independently based on the best
-  // choice for the current partition. It may well be better to keep a scaled
-  // best rd so far value and update rd_thresh_freq_fact based on the mode/size
-  // combination that wins out.
-  if (cpi->sf.adaptive_rd_thresh) {
-    for (mode_index = 0; mode_index < MAX_MODES; ++mode_index) {
-      int *const fact = &cpi->rd_thresh_freq_fact[bsize][mode_index];
-
-      if (mode_index == best_mode_index) {
-        *fact -= (*fact >> 3);
-      } else {
-        *fact = MIN(*fact + RD_THRESH_INC,
-                    cpi->sf.adaptive_rd_thresh * RD_THRESH_MAX_FACT);
-      }
-    }
-  }
+  update_rd_thresh_fact(cpi, bsize, best_mode_index);
 
   // macroblock modes
   *mbmi = best_mbmode;
@@ -3759,6 +3745,7 @@
                                       PICK_MODE_CONTEXT *ctx,
                                       int64_t best_rd_so_far) {
   VP9_COMMON *const cm = &cpi->common;
+  RD_OPT *const rd_opt = &cpi->rd;
   MACROBLOCKD *const xd = &x->e_mbd;
   MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
   const struct segmentation *const seg = &cm->seg;
@@ -3777,7 +3764,7 @@
   int64_t best_filter_rd[SWITCHABLE_FILTER_CONTEXTS];
   int64_t best_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
   MB_MODE_INFO best_mbmode = { 0 };
-  int mode_index, best_mode_index = 0;
+  int ref_index, best_ref_index = 0;
   unsigned int ref_costs_single[MAX_REF_FRAMES], ref_costs_comp[MAX_REF_FRAMES];
   vp9_prob comp_mode_p;
   int64_t best_inter_rd = INT64_MAX;
@@ -3786,7 +3773,7 @@
   int rate_uv_intra, rate_uv_tokenonly;
   int64_t dist_uv;
   int skip_uv;
-  MB_PREDICTION_MODE mode_uv = DC_PRED;
+  PREDICTION_MODE mode_uv = DC_PRED;
   int intra_cost_penalty = 20 * vp9_dc_quant(cm->base_qindex, cm->y_dc_delta_q);
   int_mv seg_mvs[4][MAX_REF_FRAMES];
   b_mode_info best_bmodes[4];
@@ -3803,7 +3790,7 @@
       seg_mvs[i][j].as_int = INVALID_MV;
   }
 
-  estimate_ref_frame_costs(cpi, segment_id, ref_costs_single, ref_costs_comp,
+  estimate_ref_frame_costs(cm, xd, segment_id, ref_costs_single, ref_costs_comp,
                            &comp_mode_p);
 
   for (i = 0; i < REFERENCE_MODES; ++i)
@@ -3836,7 +3823,7 @@
     }
   }
 
-  for (mode_index = 0; mode_index < MAX_REFS; ++mode_index) {
+  for (ref_index = 0; ref_index < MAX_REFS; ++ref_index) {
     int mode_excluded = 0;
     int64_t this_rd = INT64_MAX;
     int disable_skip = 0;
@@ -3849,14 +3836,14 @@
     int64_t total_sse = INT_MAX;
     int early_term = 0;
 
-    ref_frame = vp9_ref_order[mode_index].ref_frame[0];
-    second_ref_frame = vp9_ref_order[mode_index].ref_frame[1];
+    ref_frame = vp9_ref_order[ref_index].ref_frame[0];
+    second_ref_frame = vp9_ref_order[ref_index].ref_frame[1];
 
     // Look at the reference frame of the best mode so far and set the
     // skip mask to look at a subset of the remaining modes.
-    if (mode_index > 2 && cpi->sf.mode_skip_start < MAX_MODES) {
-      if (mode_index == 3) {
-        switch (vp9_ref_order[best_mode_index].ref_frame[0]) {
+    if (ref_index > 2 && cpi->sf.mode_skip_start < MAX_MODES) {
+      if (ref_index == 3) {
+        switch (vp9_ref_order[best_ref_index].ref_frame[0]) {
           case INTRA_FRAME:
             mode_skip_mask = 0;
             break;
@@ -3874,15 +3861,14 @@
             assert(0 && "Invalid Reference frame");
         }
       }
-      if (mode_skip_mask & (1 << mode_index))
+      if (mode_skip_mask & (1 << ref_index))
         continue;
     }
 
     // Test best rd so far against threshold for trying this mode.
-    if ((best_rd <
-         ((int64_t)cpi->rd_thresh_sub8x8[segment_id][bsize][mode_index] *
-          cpi->rd_thresh_freq_sub8x8[bsize][mode_index] >> 5)) ||
-        cpi->rd_thresh_sub8x8[segment_id][bsize][mode_index] == INT_MAX)
+    if (rd_less_than_thresh(best_rd,
+                            rd_opt->threshes[segment_id][bsize][ref_index],
+                            rd_opt->thresh_freq_fact[bsize][ref_index]))
       continue;
 
     if (ref_frame > INTRA_FRAME &&
@@ -3899,7 +3885,7 @@
       if (vp9_segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME))
         continue;
       if ((cpi->sf.mode_search_skip_flags & FLAG_SKIP_COMP_BESTINTRA) &&
-          vp9_ref_order[best_mode_index].ref_frame[0] == INTRA_FRAME)
+          vp9_ref_order[best_ref_index].ref_frame[0] == INTRA_FRAME)
         continue;
       if ((cpi->sf.mode_search_skip_flags & FLAG_SKIP_COMP_REFMISMATCH) &&
           ref_frame != best_inter_ref_frame &&
@@ -3909,10 +3895,11 @@
 
     // TODO(jingning, jkoleszar): scaling reference frame not supported for
     // sub8x8 blocks.
-    if (ref_frame > NONE && vp9_is_scaled(&cm->frame_refs[ref_frame - 1].sf))
+    if (ref_frame > INTRA_FRAME &&
+        vp9_is_scaled(&cm->frame_refs[ref_frame - 1].sf))
       continue;
 
-    if (second_ref_frame > NONE &&
+    if (second_ref_frame > INTRA_FRAME &&
         vp9_is_scaled(&cm->frame_refs[second_ref_frame - 1].sf))
       continue;
 
@@ -4011,14 +3998,13 @@
       int uv_skippable;
 
       this_rd_thresh = (ref_frame == LAST_FRAME) ?
-          cpi->rd_thresh_sub8x8[segment_id][bsize][THR_LAST] :
-          cpi->rd_thresh_sub8x8[segment_id][bsize][THR_ALTR];
+          rd_opt->threshes[segment_id][bsize][THR_LAST] :
+          rd_opt->threshes[segment_id][bsize][THR_ALTR];
       this_rd_thresh = (ref_frame == GOLDEN_FRAME) ?
-          cpi->rd_thresh_sub8x8[segment_id][bsize][THR_GOLD] : this_rd_thresh;
-
-      cpi->mask_filter_rd = 0;
+      rd_opt->threshes[segment_id][bsize][THR_GOLD] : this_rd_thresh;
+      rd_opt->mask_filter = 0;
       for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
-        cpi->rd_filter_cache[i] = INT64_MAX;
+        rd_opt->filter_cache[i] = INT64_MAX;
 
       if (cm->interp_filter != BILINEAR) {
         tmp_best_filter = EIGHTTAP;
@@ -4037,28 +4023,27 @@
             int newbest, rs;
             int64_t rs_rd;
             mbmi->interp_filter = switchable_filter_index;
-            tmp_rd = rd_pick_best_mbsegmentation(cpi, x, tile,
-                                                 &mbmi->ref_mvs[ref_frame][0],
-                                                 second_ref,
-                                                 best_yrd,
-                                                 &rate, &rate_y, &distortion,
-                                                 &skippable, &total_sse,
-                                                 (int)this_rd_thresh, seg_mvs,
-                                                 bsi, switchable_filter_index,
-                                                 mi_row, mi_col);
+            tmp_rd = rd_pick_best_sub8x8_mode(cpi, x, tile,
+                                              &mbmi->ref_mvs[ref_frame][0],
+                                              second_ref, best_yrd, &rate,
+                                              &rate_y, &distortion,
+                                              &skippable, &total_sse,
+                                              (int) this_rd_thresh, seg_mvs,
+                                              bsi, switchable_filter_index,
+                                              mi_row, mi_col);
 
             if (tmp_rd == INT64_MAX)
               continue;
             rs = vp9_get_switchable_rate(x);
             rs_rd = RDCOST(x->rdmult, x->rddiv, rs, 0);
-            cpi->rd_filter_cache[switchable_filter_index] = tmp_rd;
-            cpi->rd_filter_cache[SWITCHABLE_FILTERS] =
-                MIN(cpi->rd_filter_cache[SWITCHABLE_FILTERS],
+            rd_opt->filter_cache[switchable_filter_index] = tmp_rd;
+            rd_opt->filter_cache[SWITCHABLE_FILTERS] =
+                MIN(rd_opt->filter_cache[SWITCHABLE_FILTERS],
                     tmp_rd + rs_rd);
             if (cm->interp_filter == SWITCHABLE)
               tmp_rd += rs_rd;
 
-            cpi->mask_filter_rd = MAX(cpi->mask_filter_rd, tmp_rd);
+            rd_opt->mask_filter = MAX(rd_opt->mask_filter, tmp_rd);
 
             newbest = (tmp_rd < tmp_best_rd);
             if (newbest) {
@@ -4104,15 +4089,12 @@
       if (!pred_exists) {
         // Handles the special case when a filter that is not in the
         // switchable list (bilinear, 6-tap) is indicated at the frame level
-        tmp_rd = rd_pick_best_mbsegmentation(cpi, x, tile,
-                     &mbmi->ref_mvs[ref_frame][0],
-                     second_ref,
-                     best_yrd,
-                     &rate, &rate_y, &distortion,
-                     &skippable, &total_sse,
-                     (int)this_rd_thresh, seg_mvs,
-                     bsi, 0,
-                     mi_row, mi_col);
+        tmp_rd = rd_pick_best_sub8x8_mode(cpi, x, tile,
+                                          &mbmi->ref_mvs[ref_frame][0],
+                                          second_ref, best_yrd, &rate, &rate_y,
+                                          &distortion, &skippable, &total_sse,
+                                          (int) this_rd_thresh, seg_mvs, bsi, 0,
+                                          mi_row, mi_col);
         if (tmp_rd == INT64_MAX)
           continue;
       } else {
@@ -4223,7 +4205,7 @@
       if (!mode_excluded) {
         int max_plane = MAX_MB_PLANE;
         // Note index of best mode so far
-        best_mode_index = mode_index;
+        best_ref_index = ref_index;
 
         if (ref_frame == INTRA_FRAME) {
           /* required for left and above block mv */
@@ -4249,7 +4231,7 @@
         // TODO(debargha): enhance this test with a better distortion prediction
         // based on qp, activity mask and history
         if ((cpi->sf.mode_search_skip_flags & FLAG_EARLY_TERMINATE) &&
-            (mode_index > MIN_EARLY_TERM_INDEX)) {
+            (ref_index > MIN_EARLY_TERM_INDEX)) {
           const int qstep = xd->plane[0].dequant[1];
           // TODO(debargha): Enhance this by specializing for each mode_index
           int scale = 4;
@@ -4292,20 +4274,20 @@
     /* keep record of best filter type */
     if (!mode_excluded && !disable_skip && ref_frame != INTRA_FRAME &&
         cm->interp_filter != BILINEAR) {
-      int64_t ref = cpi->rd_filter_cache[cm->interp_filter == SWITCHABLE ?
+      int64_t ref = rd_opt->filter_cache[cm->interp_filter == SWITCHABLE ?
                               SWITCHABLE_FILTERS : cm->interp_filter];
       int64_t adj_rd;
       for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
         if (ref == INT64_MAX)
           adj_rd = 0;
-        else if (cpi->rd_filter_cache[i] == INT64_MAX)
+        else if (rd_opt->filter_cache[i] == INT64_MAX)
           // when early termination is triggered, the encoder does not have
           // access to the rate-distortion cost. it only knows that the cost
           // should be above the maximum valid value. hence it takes the known
           // maximum plus an arbitrary constant as the rate-distortion cost.
-          adj_rd = cpi->mask_filter_rd - ref + 10;
+          adj_rd = rd_opt->mask_filter - ref + 10;
         else
-          adj_rd = cpi->rd_filter_cache[i] - ref;
+          adj_rd = rd_opt->filter_cache[i] - ref;
 
         adj_rd += this_rd;
         best_filter_rd[i] = MIN(best_filter_rd[i], adj_rd);
@@ -4325,7 +4307,7 @@
   // If we used an estimate for the uv intra rd in the loop above...
   if (cpi->sf.use_uv_intra_rd_estimate) {
     // Do Intra UV best rd mode selection if best mode choice above was intra.
-    if (vp9_ref_order[best_mode_index].ref_frame[0] == INTRA_FRAME) {
+    if (vp9_ref_order[best_ref_index].ref_frame[0] == INTRA_FRAME) {
       *mbmi = best_mbmode;
       rd_pick_intra_sbuv_mode(cpi, x, ctx, &rate_uv_intra,
                               &rate_uv_tokenonly,
@@ -4345,23 +4327,7 @@
          (cm->interp_filter == best_mbmode.interp_filter) ||
          !is_inter_block(&best_mbmode));
 
-  // Updating rd_thresh_freq_fact[] here means that the different
-  // partition/block sizes are handled independently based on the best
-  // choice for the current partition. It may well be better to keep a scaled
-  // best rd so far value and update rd_thresh_freq_fact based on the mode/size
-  // combination that wins out.
-  if (cpi->sf.adaptive_rd_thresh) {
-    for (mode_index = 0; mode_index < MAX_REFS; ++mode_index) {
-      int *const fact = &cpi->rd_thresh_freq_sub8x8[bsize][mode_index];
-
-      if (mode_index == best_mode_index) {
-        *fact -= (*fact >> 3);
-      } else {
-        *fact = MIN(*fact + RD_THRESH_INC,
-                    cpi->sf.adaptive_rd_thresh * RD_THRESH_MAX_FACT);
-      }
-    }
-  }
+  update_rd_thresh_fact(cpi, bsize, best_ref_index);
 
   // macroblock modes
   *mbmi = best_mbmode;
@@ -4398,7 +4364,7 @@
   }
 
   set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
-  store_coding_context(x, ctx, best_mode_index,
+  store_coding_context(x, ctx, best_ref_index,
                        &mbmi->ref_mvs[mbmi->ref_frame[0]][0],
                        &mbmi->ref_mvs[mbmi->ref_frame[1] < 0 ? 0 :
                                       mbmi->ref_frame[1]][0],
@@ -4406,3 +4372,120 @@
 
   return best_rd;
 }
+
+void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
+  int i;
+  RD_OPT *const rd = &cpi->rd;
+
+  // Set baseline threshold values
+  for (i = 0; i < MAX_MODES; ++i)
+    rd->thresh_mult[i] = is_best_mode(cpi->oxcf.mode) ? -500 : 0;
+
+  rd->thresh_mult[THR_NEARESTMV] = 0;
+  rd->thresh_mult[THR_NEARESTG] = 0;
+  rd->thresh_mult[THR_NEARESTA] = 0;
+
+  rd->thresh_mult[THR_DC] += 1000;
+
+  rd->thresh_mult[THR_NEWMV] += 1000;
+  rd->thresh_mult[THR_NEWA] += 1000;
+  rd->thresh_mult[THR_NEWG] += 1000;
+
+  rd->thresh_mult[THR_NEARMV] += 1000;
+  rd->thresh_mult[THR_NEARA] += 1000;
+  rd->thresh_mult[THR_COMP_NEARESTLA] += 1000;
+  rd->thresh_mult[THR_COMP_NEARESTGA] += 1000;
+
+  rd->thresh_mult[THR_TM] += 1000;
+
+  rd->thresh_mult[THR_COMP_NEARLA] += 1500;
+  rd->thresh_mult[THR_COMP_NEWLA] += 2000;
+  rd->thresh_mult[THR_NEARG] += 1000;
+  rd->thresh_mult[THR_COMP_NEARGA] += 1500;
+  rd->thresh_mult[THR_COMP_NEWGA] += 2000;
+
+  rd->thresh_mult[THR_ZEROMV] += 2000;
+  rd->thresh_mult[THR_ZEROG] += 2000;
+  rd->thresh_mult[THR_ZEROA] += 2000;
+  rd->thresh_mult[THR_COMP_ZEROLA] += 2500;
+  rd->thresh_mult[THR_COMP_ZEROGA] += 2500;
+
+  rd->thresh_mult[THR_H_PRED] += 2000;
+  rd->thresh_mult[THR_V_PRED] += 2000;
+  rd->thresh_mult[THR_D45_PRED ] += 2500;
+  rd->thresh_mult[THR_D135_PRED] += 2500;
+  rd->thresh_mult[THR_D117_PRED] += 2500;
+  rd->thresh_mult[THR_D153_PRED] += 2500;
+  rd->thresh_mult[THR_D207_PRED] += 2500;
+  rd->thresh_mult[THR_D63_PRED] += 2500;
+
+  /* disable frame modes if flags not set */
+  if (!(cpi->ref_frame_flags & VP9_LAST_FLAG)) {
+    rd->thresh_mult[THR_NEWMV    ] = INT_MAX;
+    rd->thresh_mult[THR_NEARESTMV] = INT_MAX;
+    rd->thresh_mult[THR_ZEROMV   ] = INT_MAX;
+    rd->thresh_mult[THR_NEARMV   ] = INT_MAX;
+  }
+  if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG)) {
+    rd->thresh_mult[THR_NEARESTG ] = INT_MAX;
+    rd->thresh_mult[THR_ZEROG    ] = INT_MAX;
+    rd->thresh_mult[THR_NEARG    ] = INT_MAX;
+    rd->thresh_mult[THR_NEWG     ] = INT_MAX;
+  }
+  if (!(cpi->ref_frame_flags & VP9_ALT_FLAG)) {
+    rd->thresh_mult[THR_NEARESTA ] = INT_MAX;
+    rd->thresh_mult[THR_ZEROA    ] = INT_MAX;
+    rd->thresh_mult[THR_NEARA    ] = INT_MAX;
+    rd->thresh_mult[THR_NEWA     ] = INT_MAX;
+  }
+
+  if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
+      (VP9_LAST_FLAG | VP9_ALT_FLAG)) {
+    rd->thresh_mult[THR_COMP_ZEROLA   ] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEARESTLA] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEARLA   ] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEWLA    ] = INT_MAX;
+  }
+  if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
+      (VP9_GOLD_FLAG | VP9_ALT_FLAG)) {
+    rd->thresh_mult[THR_COMP_ZEROGA   ] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEARESTGA] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEARGA   ] = INT_MAX;
+    rd->thresh_mult[THR_COMP_NEWGA    ] = INT_MAX;
+  }
+}
+
+void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
+  const SPEED_FEATURES *const sf = &cpi->sf;
+  RD_OPT *const rd = &cpi->rd;
+  int i;
+
+  for (i = 0; i < MAX_REFS; ++i)
+    rd->thresh_mult_sub8x8[i] = is_best_mode(cpi->oxcf.mode)  ? -500 : 0;
+
+  rd->thresh_mult_sub8x8[THR_LAST] += 2500;
+  rd->thresh_mult_sub8x8[THR_GOLD] += 2500;
+  rd->thresh_mult_sub8x8[THR_ALTR] += 2500;
+  rd->thresh_mult_sub8x8[THR_INTRA] += 2500;
+  rd->thresh_mult_sub8x8[THR_COMP_LA] += 4500;
+  rd->thresh_mult_sub8x8[THR_COMP_GA] += 4500;
+
+  // Check for masked out split cases.
+  for (i = 0; i < MAX_REFS; i++)
+    if (sf->disable_split_mask & (1 << i))
+      rd->thresh_mult_sub8x8[i] = INT_MAX;
+
+  // disable mode test if frame flag is not set
+  if (!(cpi->ref_frame_flags & VP9_LAST_FLAG))
+    rd->thresh_mult_sub8x8[THR_LAST] = INT_MAX;
+  if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG))
+    rd->thresh_mult_sub8x8[THR_GOLD] = INT_MAX;
+  if (!(cpi->ref_frame_flags & VP9_ALT_FLAG))
+    rd->thresh_mult_sub8x8[THR_ALTR] = INT_MAX;
+  if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
+      (VP9_LAST_FLAG | VP9_ALT_FLAG))
+    rd->thresh_mult_sub8x8[THR_COMP_LA] = INT_MAX;
+  if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
+      (VP9_GOLD_FLAG | VP9_ALT_FLAG))
+    rd->thresh_mult_sub8x8[THR_COMP_GA] = INT_MAX;
+}
diff --git a/vp9/encoder/vp9_rdopt.h b/vp9/encoder/vp9_rdopt.h
index a01dbd4..cd622d6 100644
--- a/vp9/encoder/vp9_rdopt.h
+++ b/vp9/encoder/vp9_rdopt.h
@@ -11,7 +11,7 @@
 #ifndef VP9_ENCODER_VP9_RDOPT_H_
 #define VP9_ENCODER_VP9_RDOPT_H_
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -83,6 +83,10 @@
                               ENTROPY_CONTEXT t_above[16],
                               ENTROPY_CONTEXT t_left[16]);
 
+void vp9_set_rd_speed_thresholds(VP9_COMP *cpi);
+
+void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/vp9/encoder/vp9_sad.c b/vp9/encoder/vp9_sad.c
index 9d8da0d..892e905 100644
--- a/vp9/encoder/vp9_sad.c
+++ b/vp9/encoder/vp9_sad.c
@@ -33,292 +33,105 @@
   return sad;
 }
 
-#define sad_mxn_func(m, n) \
-unsigned int vp9_sad##m##x##n##_c(const uint8_t *src_ptr, int src_stride, \
-                                  const uint8_t *ref_ptr, int ref_stride, \
+#define sadMxN(m, n) \
+unsigned int vp9_sad##m##x##n##_c(const uint8_t *src, int src_stride, \
+                                  const uint8_t *ref, int ref_stride, \
                                   unsigned int max_sad) { \
-  return sad(src_ptr, src_stride, ref_ptr, ref_stride, m, n); \
+  return sad(src, src_stride, ref, ref_stride, m, n); \
 } \
-unsigned int vp9_sad##m##x##n##_avg_c(const uint8_t *src_ptr, int src_stride, \
-                                      const uint8_t *ref_ptr, int ref_stride, \
+unsigned int vp9_sad##m##x##n##_avg_c(const uint8_t *src, int src_stride, \
+                                      const uint8_t *ref, int ref_stride, \
                                       const uint8_t *second_pred, \
                                       unsigned int max_sad) { \
   uint8_t comp_pred[m * n]; \
-  vp9_comp_avg_pred(comp_pred, second_pred, m, n, ref_ptr, ref_stride); \
-  return sad(src_ptr, src_stride, comp_pred, m, m, n); \
+  vp9_comp_avg_pred(comp_pred, second_pred, m, n, ref, ref_stride); \
+  return sad(src, src_stride, comp_pred, m, m, n); \
 }
 
-sad_mxn_func(64, 64)
-sad_mxn_func(64, 32)
-sad_mxn_func(32, 64)
-sad_mxn_func(32, 32)
-sad_mxn_func(32, 16)
-sad_mxn_func(16, 32)
-sad_mxn_func(16, 16)
-sad_mxn_func(16, 8)
-sad_mxn_func(8, 16)
-sad_mxn_func(8, 8)
-sad_mxn_func(8, 4)
-sad_mxn_func(4, 8)
-sad_mxn_func(4, 4)
-
-void vp9_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad64x32(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
+#define sadMxNxK(m, n, k) \
+void vp9_sad##m##x##n##x##k##_c(const uint8_t *src, int src_stride, \
+                                const uint8_t *ref, int ref_stride, \
+                                unsigned int *sads) { \
+  int i; \
+  for (i = 0; i < k; ++i) \
+    sads[i] = vp9_sad##m##x##n##_c(src, src_stride, &ref[i], ref_stride, \
+                                   0x7fffffff); \
 }
 
-void vp9_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad32x64(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
+#define sadMxNx4D(m, n) \
+void vp9_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride, \
+                             const uint8_t *const refs[], int ref_stride, \
+                             unsigned int *sads) { \
+  int i; \
+  for (i = 0; i < 4; ++i) \
+    sads[i] = vp9_sad##m##x##n##_c(src, src_stride, refs[i], ref_stride, \
+                                   0x7fffffff); \
 }
 
-void vp9_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad32x16(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
-}
+// 64x64
+sadMxN(64, 64)
+sadMxNxK(64, 64, 3)
+sadMxNxK(64, 64, 8)
+sadMxNx4D(64, 64)
 
-void vp9_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad16x32(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
-}
+// 64x32
+sadMxN(64, 32)
+sadMxNx4D(64, 32)
 
-void vp9_sad64x64x3_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad64x64(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 32x64
+sadMxN(32, 64)
+sadMxNx4D(32, 64)
 
-void vp9_sad32x32x3_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad32x32(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 32x32
+sadMxN(32, 32)
+sadMxNxK(32, 32, 3)
+sadMxNxK(32, 32, 8)
+sadMxNx4D(32, 32)
 
-void vp9_sad64x64x8_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad64x64(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 32x16
+sadMxN(32, 16)
+sadMxNx4D(32, 16)
 
-void vp9_sad32x32x8_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad32x32(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 16x32
+sadMxN(16, 32)
+sadMxNx4D(16, 32)
 
-void vp9_sad16x16x3_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad16x16(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 16x16
+sadMxN(16, 16)
+sadMxNxK(16, 16, 3)
+sadMxNxK(16, 16, 8)
+sadMxNx4D(16, 16)
 
-void vp9_sad16x16x8_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t *ref_ptr, int ref_stride,
-                      uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad16x16(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                                0x7fffffff);
-}
+// 16x8
+sadMxN(16, 8)
+sadMxNxK(16, 8, 3)
+sadMxNxK(16, 8, 8)
+sadMxNx4D(16, 8)
 
-void vp9_sad16x8x3_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t *ref_ptr, int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad16x8(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                               0x7fffffff);
-}
+// 8x16
+sadMxN(8, 16)
+sadMxNxK(8, 16, 3)
+sadMxNxK(8, 16, 8)
+sadMxNx4D(8, 16)
 
-void vp9_sad16x8x8_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t *ref_ptr, int ref_stride,
-                     uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad16x8(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                               0x7fffffff);
-}
+// 8x8
+sadMxN(8, 8)
+sadMxNxK(8, 8, 3)
+sadMxNxK(8, 8, 8)
+sadMxNx4D(8, 8)
 
-void vp9_sad8x8x3_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad8x8(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
+// 8x4
+sadMxN(8, 4)
+sadMxNxK(8, 4, 8)
+sadMxNx4D(8, 4)
 
-void vp9_sad8x8x8_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad8x8(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
+// 4x8
+sadMxN(4, 8)
+sadMxNxK(4, 8, 8)
+sadMxNx4D(4, 8)
 
-void vp9_sad8x16x3_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t *ref_ptr, int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad8x16(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                               0x7fffffff);
-}
-
-void vp9_sad8x16x8_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t *ref_ptr, int ref_stride,
-                     uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad8x16(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                               0x7fffffff);
-}
-
-void vp9_sad4x4x3_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 3; ++i)
-    sad_array[i] = vp9_sad4x4(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad4x4x8_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad4x4(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad64x64x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad64x64(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
-}
-
-void vp9_sad32x32x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad32x32(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
-}
-
-void vp9_sad16x16x4d_c(const uint8_t *src_ptr, int src_stride,
-                       const uint8_t* const ref_ptr[], int ref_stride,
-                       unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad16x16(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                                0x7fffffff);
-}
-
-void vp9_sad16x8x4d_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t* const ref_ptr[], int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad16x8(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                               0x7fffffff);
-}
-
-void vp9_sad8x8x4d_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t* const ref_ptr[], int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad8x8(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad8x16x4d_c(const uint8_t *src_ptr, int src_stride,
-                      const uint8_t* const ref_ptr[], int ref_stride,
-                      unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad8x16(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                               0x7fffffff);
-}
-
-void vp9_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t* const ref_ptr[], int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad8x4(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad8x4x8_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad8x4(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t* const ref_ptr[], int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad4x8(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad4x8x8_c(const uint8_t *src_ptr, int src_stride,
-                    const uint8_t *ref_ptr, int ref_stride,
-                    uint32_t *sad_array) {
-  int i;
-  for (i = 0; i < 8; ++i)
-    sad_array[i] = vp9_sad4x8(src_ptr, src_stride, ref_ptr + i, ref_stride,
-                              0x7fffffff);
-}
-
-void vp9_sad4x4x4d_c(const uint8_t *src_ptr, int src_stride,
-                     const uint8_t* const ref_ptr[], int ref_stride,
-                     unsigned int *sad_array) {
-  int i;
-  for (i = 0; i < 4; ++i)
-    sad_array[i] = vp9_sad4x4(src_ptr, src_stride, ref_ptr[i], ref_stride,
-                              0x7fffffff);
-}
+// 4x4
+sadMxN(4, 4)
+sadMxNxK(4, 4, 3)
+sadMxNxK(4, 4, 8)
+sadMxNx4D(4, 4)
diff --git a/vp9/encoder/vp9_segmentation.c b/vp9/encoder/vp9_segmentation.c
index 9d3e6dc..7537d1b 100644
--- a/vp9/encoder/vp9_segmentation.c
+++ b/vp9/encoder/vp9_segmentation.c
@@ -29,18 +29,6 @@
   seg->enabled = 0;
 }
 
-void vp9_set_segmentation_map(VP9_COMP *cpi, unsigned char *segmentation_map) {
-  struct segmentation *const seg = &cpi->common.seg;
-
-  // Copy in the new segmentation map
-  vpx_memcpy(cpi->segmentation_map, segmentation_map,
-             (cpi->common.mi_rows * cpi->common.mi_cols));
-
-  // Signal that the map should be updated.
-  seg->update_map = 1;
-  seg->update_data = 1;
-}
-
 void vp9_set_segment_data(struct segmentation *seg,
                           signed char *feature_data,
                           unsigned char abs_delta) {
diff --git a/vp9/encoder/vp9_segmentation.h b/vp9/encoder/vp9_segmentation.h
index 66c51a2..50dd562 100644
--- a/vp9/encoder/vp9_segmentation.h
+++ b/vp9/encoder/vp9_segmentation.h
@@ -13,7 +13,7 @@
 #define VP9_ENCODER_VP9_SEGMENTATION_H_
 
 #include "vp9/common/vp9_blockd.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,9 +28,6 @@
 void vp9_clear_segdata(struct segmentation *seg,
                        int segment_id,
                        SEG_LVL_FEATURES feature_id);
-// Valid values for a segment are 0 to 3
-// Segmentation map is arrange as [Rows][Columns]
-void vp9_set_segmentation_map(VP9_COMP *cpi, unsigned char *segmentation_map);
 
 // The values given for each segment can be either deltas (from the default
 // value chosen for the frame) or absolute values.
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index adad800..93e23ee 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -10,35 +10,42 @@
 
 #include <limits.h>
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_speed_features.h"
 
-#define ALL_INTRA_MODES ((1 << DC_PRED) | \
-                         (1 << V_PRED) | (1 << H_PRED) | \
-                         (1 << D45_PRED) | (1 << D135_PRED) | \
-                         (1 << D117_PRED) | (1 << D153_PRED) | \
-                         (1 << D207_PRED) | (1 << D63_PRED) | \
-                         (1 << TM_PRED))
-#define INTRA_DC_ONLY   (1 << DC_PRED)
-#define INTRA_DC_TM     ((1 << TM_PRED) | (1 << DC_PRED))
-#define INTRA_DC_H_V    ((1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED))
-#define INTRA_DC_TM_H_V (INTRA_DC_TM | (1 << V_PRED) | (1 << H_PRED))
+enum {
+  ALL_INTRA_MODES = (1 << DC_PRED) |
+                    (1 << V_PRED) | (1 << H_PRED) |
+                    (1 << D45_PRED) | (1 << D135_PRED) |
+                    (1 << D117_PRED) | (1 << D153_PRED) |
+                    (1 << D207_PRED) | (1 << D63_PRED) |
+                    (1 << TM_PRED),
 
-// Masks for partially or completely disabling split mode
-#define DISABLE_ALL_INTER_SPLIT   ((1 << THR_COMP_GA) | \
-                                   (1 << THR_COMP_LA) | \
-                                   (1 << THR_ALTR) | \
-                                   (1 << THR_GOLD) | \
-                                   (1 << THR_LAST))
+  INTRA_DC_ONLY   = (1 << DC_PRED),
 
-#define DISABLE_ALL_SPLIT         ((1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT)
+  INTRA_DC_TM     = (1 << TM_PRED) | (1 << DC_PRED),
 
-#define DISABLE_COMPOUND_SPLIT    ((1 << THR_COMP_GA) | (1 << THR_COMP_LA))
+  INTRA_DC_H_V    = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED),
 
-#define LAST_AND_INTRA_SPLIT_ONLY ((1 << THR_COMP_GA) | \
-                                   (1 << THR_COMP_LA) | \
-                                   (1 << THR_ALTR) | \
-                                   (1 << THR_GOLD))
+  INTRA_DC_TM_H_V = INTRA_DC_TM | (1 << V_PRED) | (1 << H_PRED)
+};
+
+enum {
+  DISABLE_ALL_INTER_SPLIT   = (1 << THR_COMP_GA) |
+                              (1 << THR_COMP_LA) |
+                              (1 << THR_ALTR) |
+                              (1 << THR_GOLD) |
+                              (1 << THR_LAST),
+
+  DISABLE_ALL_SPLIT         = (1 << THR_INTRA) | DISABLE_ALL_INTER_SPLIT,
+
+  DISABLE_COMPOUND_SPLIT    = (1 << THR_COMP_GA) | (1 << THR_COMP_LA),
+
+  LAST_AND_INTRA_SPLIT_ONLY = (1 << THR_COMP_GA) |
+                              (1 << THR_COMP_LA) |
+                              (1 << THR_ALTR) |
+                              (1 << THR_GOLD)
+};
 
 static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm,
                                    SPEED_FEATURES *sf, int speed) {
@@ -49,8 +56,8 @@
   if (speed >= 1) {
     sf->use_square_partition_only = !frame_is_intra_only(cm);
     sf->less_rectangular_check  = 1;
-    sf->tx_size_search_method = vp9_frame_is_boosted(cpi) ? USE_FULL_RD
-                                                          : USE_LARGESTALL;
+    sf->tx_size_search_method = frame_is_boosted(cpi) ? USE_FULL_RD
+                                                      : USE_LARGESTALL;
 
     if (MIN(cm->width, cm->height) >= 720)
       sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
@@ -73,9 +80,6 @@
   }
 
   if (speed >= 2) {
-    sf->tx_size_search_method = vp9_frame_is_boosted(cpi) ? USE_FULL_RD
-                                                          : USE_LARGESTALL;
-
     if (MIN(cm->width, cm->height) >= 720)
       sf->disable_split_mask = cm->show_frame ? DISABLE_ALL_SPLIT
                                               : DISABLE_ALL_INTER_SPLIT;
@@ -97,6 +101,8 @@
   }
 
   if (speed >= 3) {
+    sf->tx_size_search_method = frame_is_intra_only(cm) ? USE_FULL_RD
+                                                        : USE_LARGESTALL;
     if (MIN(cm->width, cm->height) >= 720)
       sf->disable_split_mask = DISABLE_ALL_SPLIT;
     else
@@ -262,6 +268,7 @@
     sf->use_nonrd_pick_mode = 1;
     sf->search_method = FAST_DIAMOND;
     sf->allow_skip_recode = 0;
+    sf->chessboard_index = cm->current_video_frame & 0x01;
   }
 
   if (speed >= 6) {
@@ -281,8 +288,7 @@
 void vp9_set_speed_features(VP9_COMP *cpi) {
   SPEED_FEATURES *const sf = &cpi->sf;
   VP9_COMMON *const cm = &cpi->common;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
-  const int speed = cpi->speed < 0 ? -cpi->speed : cpi->speed;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   int i;
 
   // best quality defaults
@@ -346,17 +352,17 @@
   sf->recode_tolerance = 25;
 
   switch (oxcf->mode) {
-    case MODE_BESTQUALITY:
-    case MODE_SECONDPASS_BEST:  // This is the best quality mode.
+    case ONE_PASS_BEST:
+    case TWO_PASS_SECOND_BEST:  // This is the best quality mode.
       cpi->diamond_search_sad = vp9_full_range_search;
       break;
-    case MODE_FIRSTPASS:
-    case MODE_GOODQUALITY:
-    case MODE_SECONDPASS:
-      set_good_speed_feature(cpi, cm, sf, speed);
+    case TWO_PASS_FIRST:
+    case ONE_PASS_GOOD:
+    case TWO_PASS_SECOND_GOOD:
+      set_good_speed_feature(cpi, cm, sf, oxcf->speed);
       break;
-    case MODE_REALTIME:
-      set_rt_speed_feature(cm, sf, speed);
+    case REALTIME:
+      set_rt_speed_feature(cm, sf, oxcf->speed);
       break;
   }
 
@@ -378,7 +384,7 @@
 
   cpi->mb.optimize = sf->optimize_coefficients == 1 && cpi->pass != 1;
 
-  if (cpi->encode_breakout && oxcf->mode == MODE_REALTIME &&
+  if (cpi->encode_breakout && oxcf->mode == REALTIME &&
       sf->encode_breakout_thresh > cpi->encode_breakout)
     cpi->encode_breakout = sf->encode_breakout_thresh;
 
diff --git a/vp9/encoder/vp9_speed_features.h b/vp9/encoder/vp9_speed_features.h
index 72f548a..cff99a6 100644
--- a/vp9/encoder/vp9_speed_features.h
+++ b/vp9/encoder/vp9_speed_features.h
@@ -274,6 +274,9 @@
   // encoding process for RTC.
   int partition_check;
 
+  // Chessboard pattern index
+  int chessboard_index;
+
   // Use finer quantizer in every other few frames that run variable block
   // partition type search.
   int force_frame_boost;
@@ -344,7 +347,7 @@
   int search_type_check_frequency;
 
   // The threshold used in SOURCE_VAR_BASED_PARTITION search type.
-  int source_var_thresh;
+  unsigned int source_var_thresh;
 } SPEED_FEATURES;
 
 struct VP9_COMP;
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index c2b6263..792e8d2 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -10,12 +10,12 @@
 
 #include <math.h>
 
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_svc_layercontext.h"
 
 void vp9_init_layer_context(VP9_COMP *const cpi) {
   SVC *const svc = &cpi->svc;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   int layer;
   int layer_end;
 
@@ -65,7 +65,7 @@
 void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
                                             const int target_bandwidth) {
   SVC *const svc = &cpi->svc;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   const RATE_CONTROL *const rc = &cpi->rc;
   int layer;
   int layer_end;
@@ -102,7 +102,7 @@
     } else {
       lc->framerate = oxcf->framerate;
     }
-    lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+    lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
     lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
     // Update qp-related quantities.
     lrc->worst_quality = rc->worst_quality;
@@ -118,17 +118,17 @@
 
 void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
   SVC *const svc = &cpi->svc;
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   LAYER_CONTEXT *const lc = get_layer_context(svc);
   RATE_CONTROL *const lrc = &lc->rc;
   const int layer = svc->temporal_layer_id;
 
   lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
-  lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+  lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
   lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
   // Update the average layer frame size (non-cumulative per-frame-bw).
   if (layer == 0) {
-    lc->avg_frame_size = lrc->av_per_frame_bandwidth;
+    lc->avg_frame_size = lrc->avg_frame_bandwidth;
   } else {
     const double prev_layer_framerate =
         oxcf->framerate / oxcf->ts_rate_decimator[layer - 1];
@@ -141,19 +141,19 @@
 }
 
 void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
   RATE_CONTROL *const lrc = &lc->rc;
 
   lc->framerate = framerate;
-  lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
-  lrc->min_frame_bandwidth = (int)(lrc->av_per_frame_bandwidth *
+  lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+  lrc->min_frame_bandwidth = (int)(lrc->avg_frame_bandwidth *
                                    oxcf->two_pass_vbrmin_section / 100);
-  lrc->max_frame_bandwidth = (int)(((int64_t)lrc->av_per_frame_bandwidth *
+  lrc->max_frame_bandwidth = (int)(((int64_t)lrc->avg_frame_bandwidth *
                                    oxcf->two_pass_vbrmax_section) / 100);
   lrc->max_gf_interval = 16;
 
-  lrc->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;
+  lrc->static_scene_max_gf_interval = cpi->oxcf.key_freq >> 1;
 
   if (oxcf->play_alternate && oxcf->lag_in_frames) {
     if (lrc->max_gf_interval > oxcf->lag_in_frames - 1)
@@ -178,7 +178,6 @@
   cpi->oxcf.starting_buffer_level = lc->starting_buffer_level;
   cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level;
   cpi->oxcf.maximum_buffer_size = lc->maximum_buffer_size;
-  cpi->output_framerate = lc->framerate;
   // Reset the frames_since_key and frames_to_key counters to their values
   // before the layer restore. Keep these defined for the stream (not layer).
   if (cpi->svc.number_temporal_layers > 1) {
@@ -188,7 +187,7 @@
 }
 
 void vp9_save_layer_context(VP9_COMP *const cpi) {
-  const VP9_CONFIG *const oxcf = &cpi->oxcf;
+  const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
 
   lc->rc = cpi->rc;
@@ -197,7 +196,6 @@
   lc->starting_buffer_level = oxcf->starting_buffer_level;
   lc->optimal_buffer_level = oxcf->optimal_buffer_level;
   lc->maximum_buffer_size = oxcf->maximum_buffer_size;
-  lc->framerate = cpi->output_framerate;
 }
 
 void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
@@ -222,3 +220,10 @@
       : &svc->layer_context[svc->spatial_layer_id];
   ++lc->current_video_frame_in_layer;
 }
+
+int vp9_is_upper_layer_key_frame(const VP9_COMP *cpi) {
+  return cpi->use_svc &&
+         cpi->svc.number_temporal_layers == 1 &&
+         cpi->svc.spatial_layer_id > 0 &&
+         cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame;
+}
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 2abed30..74d9c1c 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -30,6 +30,7 @@
   struct twopass_rc twopass;
   struct vpx_fixed_buf rc_twopass_stats_in;
   unsigned int current_video_frame_in_layer;
+  int is_key_frame;
 } LAYER_CONTEXT;
 
 typedef struct {
@@ -73,6 +74,9 @@
 // Increment number of video frames in layer
 void vp9_inc_frame_in_layer(SVC *svc);
 
+// Check if current layer is key frame in spatial upper layer
+int vp9_is_upper_layer_key_frame(const struct VP9_COMP *const cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index 0410273..a5234cd 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -19,7 +19,7 @@
 #include "vp9/encoder/vp9_extend.h"
 #include "vp9/encoder/vp9_firstpass.h"
 #include "vp9/encoder/vp9_mcomp.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_quantize.h"
 #include "vp9/encoder/vp9_ratectrl.h"
 #include "vp9/encoder/vp9_segmentation.h"
@@ -27,7 +27,7 @@
 #include "vpx_ports/vpx_timer.h"
 #include "vpx_scale/vpx_scale.h"
 
-#define ALT_REF_MC_ENABLED 1    // dis/enable MC in AltRef filtering
+static int fixed_divide[512];
 
 static void temporal_filter_predictors_mb_c(MACROBLOCKD *xd,
                                             uint8_t *y_mb_ptr,
@@ -80,6 +80,14 @@
                             kernel, mv_precision_uv, x, y);
 }
 
+void vp9_temporal_filter_init() {
+  int i;
+
+  fixed_divide[0] = 0;
+  for (i = 1; i < 512; ++i)
+    fixed_divide[i] = 0x80000 / i;
+}
+
 void vp9_temporal_filter_apply_c(uint8_t *frame1,
                                  unsigned int stride,
                                  uint8_t *frame2,
@@ -122,8 +130,6 @@
   }
 }
 
-#if ALT_REF_MC_ENABLED
-
 static int temporal_filter_find_matching_mb_c(VP9_COMP *cpi,
                                               uint8_t *arf_frame_buf,
                                               uint8_t *frame_ptr_buf,
@@ -133,6 +139,8 @@
   int step_param;
   int sadpb = x->sadperbit16;
   int bestsme = INT_MAX;
+  int distortion;
+  unsigned int sse;
 
   MV best_ref_mv1 = {0, 0};
   MV best_ref_mv1_full; /* full-pixel value of best_ref_mv1 */
@@ -151,33 +159,22 @@
   xd->plane[0].pre[0].buf = frame_ptr_buf;
   xd->plane[0].pre[0].stride = stride;
 
-  // Further step/diamond searches as necessary
-  if (cpi->speed < 8)
-    step_param = cpi->sf.reduce_first_step_size + ((cpi->speed > 5) ? 1 : 0);
-  else
-    step_param = cpi->sf.reduce_first_step_size + 2;
-  step_param = MIN(step_param, (cpi->sf.max_step_search_steps - 2));
+  step_param = cpi->sf.reduce_first_step_size + (cpi->oxcf.speed > 5 ? 1 : 0);
+  step_param = MIN(step_param, cpi->sf.max_step_search_steps - 2);
 
-  /*cpi->sf.search_method == HEX*/
   // Ignore mv costing by sending NULL pointer instead of cost arrays
   vp9_hex_search(x, &best_ref_mv1_full, step_param, sadpb, 1,
                  &cpi->fn_ptr[BLOCK_16X16], 0, &best_ref_mv1, ref_mv);
 
-  // Try sub-pixel MC?
-  // if (bestsme > error_thresh && bestsme < INT_MAX)
-  {
-    int distortion;
-    unsigned int sse;
-    // Ignore mv costing by sending NULL pointer instead of cost array
-    bestsme = cpi->find_fractional_mv_step(x, ref_mv,
-                                           &best_ref_mv1,
-                                           cpi->common.allow_high_precision_mv,
-                                           x->errorperbit,
-                                           &cpi->fn_ptr[BLOCK_16X16],
-                                           0, cpi->sf.subpel_iters_per_step,
-                                           NULL, NULL,
-                                           &distortion, &sse);
-  }
+  // Ignore mv costing by sending NULL pointer instead of cost array
+  bestsme = cpi->find_fractional_mv_step(x, ref_mv,
+                                         &best_ref_mv1,
+                                         cpi->common.allow_high_precision_mv,
+                                         x->errorperbit,
+                                         &cpi->fn_ptr[BLOCK_16X16],
+                                         0, cpi->sf.subpel_iters_per_step,
+                                         NULL, NULL,
+                                         &distortion, &sse);
 
   // Restore input state
   x->plane[0].src = src;
@@ -185,7 +182,6 @@
 
   return bestsme;
 }
-#endif
 
 static void temporal_filter_iterate_c(VP9_COMP *cpi,
                                       int frame_count,
@@ -219,8 +215,7 @@
     input_buffer[i] = mbd->plane[i].pre[0].buf;
 
   for (mb_row = 0; mb_row < mb_rows; mb_row++) {
-#if ALT_REF_MC_ENABLED
-    // Source frames are extended to 16 pixels.  This is different than
+    // Source frames are extended to 16 pixels. This is different than
     //  L/A/G reference frames that have a border of 32 (VP9ENCBORDERINPIXELS)
     // A 6/8 tap filter is used for motion search.  This requires 2 pixels
     //  before and 3 pixels after.  So the largest Y mv on a border would
@@ -234,7 +229,6 @@
     cpi->mb.mv_row_min = -((mb_row * 16) + (17 - 2 * VP9_INTERP_EXTEND));
     cpi->mb.mv_row_max = ((cpi->common.mb_rows - 1 - mb_row) * 16)
                          + (17 - 2 * VP9_INTERP_EXTEND);
-#endif
 
     for (mb_col = 0; mb_col < mb_cols; mb_col++) {
       int i, j, k;
@@ -243,13 +237,14 @@
       vpx_memset(accumulator, 0, 16 * 16 * 3 * sizeof(accumulator[0]));
       vpx_memset(count, 0, 16 * 16 * 3 * sizeof(count[0]));
 
-#if ALT_REF_MC_ENABLED
       cpi->mb.mv_col_min = -((mb_col * 16) + (17 - 2 * VP9_INTERP_EXTEND));
       cpi->mb.mv_col_max = ((cpi->common.mb_cols - 1 - mb_col) * 16)
                            + (17 - 2 * VP9_INTERP_EXTEND);
-#endif
 
       for (frame = 0; frame < frame_count; frame++) {
+        const int thresh_low  = 10000;
+        const int thresh_high = 20000;
+
         if (cpi->frames[frame] == NULL)
           continue;
 
@@ -259,38 +254,31 @@
         if (frame == alt_ref_index) {
           filter_weight = 2;
         } else {
-          int err = 0;
-#if ALT_REF_MC_ENABLED
-#define THRESH_LOW   10000
-#define THRESH_HIGH  20000
-
           // Find best match in this frame by MC
-          err = temporal_filter_find_matching_mb_c
-                (cpi,
-                 cpi->frames[alt_ref_index]->y_buffer + mb_y_offset,
-                 cpi->frames[frame]->y_buffer + mb_y_offset,
-                 cpi->frames[frame]->y_stride);
-#endif
+          int err = temporal_filter_find_matching_mb_c(cpi,
+              cpi->frames[alt_ref_index]->y_buffer + mb_y_offset,
+              cpi->frames[frame]->y_buffer + mb_y_offset,
+              cpi->frames[frame]->y_stride);
+
           // Assign higher weight to matching MB if it's error
           // score is lower. If not applying MC default behavior
           // is to weight all MBs equal.
-          filter_weight = err < THRESH_LOW
-                          ? 2 : err < THRESH_HIGH ? 1 : 0;
+          filter_weight = err < thresh_low
+                          ? 2 : err < thresh_high ? 1 : 0;
         }
 
         if (filter_weight != 0) {
           // Construct the predictors
-          temporal_filter_predictors_mb_c
-          (mbd,
-           cpi->frames[frame]->y_buffer + mb_y_offset,
-           cpi->frames[frame]->u_buffer + mb_uv_offset,
-           cpi->frames[frame]->v_buffer + mb_uv_offset,
-           cpi->frames[frame]->y_stride,
-           mb_uv_height,
-           mbd->mi[0]->bmi[0].as_mv[0].as_mv.row,
-           mbd->mi[0]->bmi[0].as_mv[0].as_mv.col,
-           predictor, scale,
-           mb_col * 16, mb_row * 16);
+          temporal_filter_predictors_mb_c(mbd,
+              cpi->frames[frame]->y_buffer + mb_y_offset,
+              cpi->frames[frame]->u_buffer + mb_uv_offset,
+              cpi->frames[frame]->v_buffer + mb_uv_offset,
+              cpi->frames[frame]->y_stride,
+              mb_uv_height,
+              mbd->mi[0]->bmi[0].as_mv[0].as_mv.row,
+              mbd->mi[0]->bmi[0].as_mv[0].as_mv.col,
+              predictor, scale,
+              mb_col * 16, mb_row * 16);
 
           // Apply the filter (YUV)
           vp9_temporal_filter_apply(f->y_buffer + mb_y_offset, f->y_stride,
@@ -316,7 +304,7 @@
       for (i = 0, k = 0; i < 16; i++) {
         for (j = 0; j < 16; j++, k++) {
           unsigned int pval = accumulator[k] + (count[k] >> 1);
-          pval *= cpi->fixed_divide[count[k]];
+          pval *= fixed_divide[count[k]];
           pval >>= 19;
 
           dst1[byte] = (uint8_t)pval;
@@ -324,7 +312,6 @@
           // move to next pixel
           byte++;
         }
-
         byte += stride - 16;
       }
 
@@ -338,27 +325,24 @@
 
           // U
           unsigned int pval = accumulator[k] + (count[k] >> 1);
-          pval *= cpi->fixed_divide[count[k]];
+          pval *= fixed_divide[count[k]];
           pval >>= 19;
           dst1[byte] = (uint8_t)pval;
 
           // V
           pval = accumulator[m] + (count[m] >> 1);
-          pval *= cpi->fixed_divide[count[m]];
+          pval *= fixed_divide[count[m]];
           pval >>= 19;
           dst2[byte] = (uint8_t)pval;
 
           // move to next pixel
           byte++;
         }
-
         byte += stride - mb_uv_height;
       }
-
       mb_y_offset += 16;
       mb_uv_offset += mb_uv_height;
     }
-
     mb_y_offset += 16 * (f->y_stride - mb_cols);
     mb_uv_offset += mb_uv_height * (f->uv_stride - mb_cols);
   }
@@ -370,18 +354,14 @@
 
 void vp9_temporal_filter_prepare(VP9_COMP *cpi, int distance) {
   VP9_COMMON *const cm = &cpi->common;
-
   int frame = 0;
-
   int frames_to_blur_backward = 0;
   int frames_to_blur_forward = 0;
   int frames_to_blur = 0;
   int start_frame = 0;
-
   int strength = cpi->active_arnr_strength;
   int blur_type = cpi->oxcf.arnr_type;
   int max_frames = cpi->active_arnr_frames;
-
   const int num_frames_backward = distance;
   const int num_frames_forward = vp9_lookahead_depth(cpi->lookahead)
                                - (num_frames_backward + 1);
diff --git a/vp9/encoder/vp9_temporal_filter.h b/vp9/encoder/vp9_temporal_filter.h
index 3028d78..9453dc1 100644
--- a/vp9/encoder/vp9_temporal_filter.h
+++ b/vp9/encoder/vp9_temporal_filter.h
@@ -15,6 +15,7 @@
 extern "C" {
 #endif
 
+void vp9_temporal_filter_init();
 void vp9_temporal_filter_prepare(VP9_COMP *cpi, int distance);
 void vp9_configure_arnr_filter(VP9_COMP *cpi,
                                const unsigned int frames_to_arnr,
diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c
index 291ccb3..8ce98d9 100644
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -20,7 +20,7 @@
 #include "vp9/common/vp9_seg_common.h"
 
 #include "vp9/encoder/vp9_cost.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vp9/encoder/vp9_tokenize.h"
 
 static TOKENVALUE dct_value_tokens[DCT_MAX_VALUE * 2];
diff --git a/vp9/encoder/vp9_variance.c b/vp9/encoder/vp9_variance.c
index 71867a9..ae3c86a 100644
--- a/vp9/encoder/vp9_variance.c
+++ b/vp9/encoder/vp9_variance.c
@@ -18,63 +18,34 @@
 
 #include "vp9/encoder/vp9_variance.h"
 
-void variance(const uint8_t *src_ptr,
-              int  source_stride,
-              const uint8_t *ref_ptr,
-              int  recon_stride,
-              int  w,
-              int  h,
-              unsigned int *sse,
-              int *sum) {
+void variance(const uint8_t *a, int  a_stride,
+              const uint8_t *b, int  b_stride,
+              int  w, int  h, unsigned int *sse, int *sum) {
   int i, j;
-  int diff;
 
   *sum = 0;
   *sse = 0;
 
   for (i = 0; i < h; i++) {
     for (j = 0; j < w; j++) {
-      diff = src_ptr[j] - ref_ptr[j];
+      const int diff = a[j] - b[j];
       *sum += diff;
       *sse += diff * diff;
     }
 
-    src_ptr += source_stride;
-    ref_ptr += recon_stride;
+    a += a_stride;
+    b += b_stride;
   }
 }
 
-/****************************************************************************
- *
- *  ROUTINE       : filter_block2d_bil_first_pass
- *
- *  INPUTS        : uint8_t  *src_ptr          : Pointer to source block.
- *                  uint32_t src_pixels_per_line : Stride of input block.
- *                  uint32_t pixel_step        : Offset between filter input
- *                                               samples (see notes).
- *                  uint32_t output_height     : Input block height.
- *                  uint32_t output_width      : Input block width.
- *                  int32_t  *vp9_filter       : Array of 2 bi-linear filter
- *                                               taps.
- *
- *  OUTPUTS       : int32_t *output_ptr        : Pointer to filtered block.
- *
- *  RETURNS       : void
- *
- *  FUNCTION      : Applies a 1-D 2-tap bi-linear filter to the source block in
- *                  either horizontal or vertical direction to produce the
- *                  filtered output block. Used to implement first-pass
- *                  of 2-D separable filter.
- *
- *  SPECIAL NOTES : Produces int32_t output to retain precision for next pass.
- *                  Two filter taps should sum to VP9_FILTER_WEIGHT.
- *                  pixel_step defines whether the filter is applied
- *                  horizontally (pixel_step=1) or vertically (pixel_step=
- *                  stride).
- *                  It defines the offset required to move from one input
- *                  to the next.
- *
- ****************************************************************************/
+// Applies a 1-D 2-tap bi-linear filter to the source block in either horizontal
+// or vertical direction to produce the filtered output block. Used to implement
+// first-pass of 2-D separable filter.
+//
+// Produces int32_t output to retain precision for next pass. Two filter taps
+// should sum to VP9_FILTER_WEIGHT. pixel_step defines whether the filter is
+// applied horizontally (pixel_step=1) or vertically (pixel_step=stride). It
+// defines the offset required to move from one input to the next.
 static void var_filter_block2d_bil_first_pass(const uint8_t *src_ptr,
                                               uint16_t *output_ptr,
                                               unsigned int src_pixels_per_line,
@@ -99,38 +70,14 @@
   }
 }
 
-/****************************************************************************
- *
- *  ROUTINE       : filter_block2d_bil_second_pass
- *
- *  INPUTS        : int32_t  *src_ptr          : Pointer to source block.
- *                  uint32_t src_pixels_per_line : Stride of input block.
- *                  uint32_t pixel_step        : Offset between filter input
- *                                               samples (see notes).
- *                  uint32_t output_height     : Input block height.
- *                  uint32_t output_width      : Input block width.
- *                  int32_t  *vp9_filter       : Array of 2 bi-linear filter
- *                                               taps.
- *
- *  OUTPUTS       : uint16_t *output_ptr       : Pointer to filtered block.
- *
- *  RETURNS       : void
- *
- *  FUNCTION      : Applies a 1-D 2-tap bi-linear filter to the source block in
- *                  either horizontal or vertical direction to produce the
- *                  filtered output block. Used to implement second-pass
- *                  of 2-D separable filter.
- *
- *  SPECIAL NOTES : Requires 32-bit input as produced by
- *                  filter_block2d_bil_first_pass.
- *                  Two filter taps should sum to VP9_FILTER_WEIGHT.
- *                  pixel_step defines whether the filter is applied
- *                  horizontally (pixel_step=1) or vertically (pixel_step=
- *                  stride).
- *                  It defines the offset required to move from one input
- *                  to the next.
- *
- ****************************************************************************/
+// Applies a 1-D 2-tap bi-linear filter to the source block in either horizontal
+// or vertical direction to produce the filtered output block. Used to implement
+// second-pass of 2-D separable filter.
+//
+// Requires 32-bit input as produced by filter_block2d_bil_first_pass. Two
+// filter taps should sum to VP9_FILTER_WEIGHT. pixel_step defines whether the
+// filter is applied horizontally (pixel_step=1) or vertically (pixel_step=
+// stride). It defines the offset required to move from one input to the next.
 static void var_filter_block2d_bil_second_pass(const uint16_t *src_ptr,
                                                uint8_t *output_ptr,
                                                unsigned int src_pixels_per_line,
@@ -156,266 +103,62 @@
 unsigned int vp9_get_mb_ss_c(const int16_t *src_ptr) {
   unsigned int i, sum = 0;
 
-  for (i = 0; i < 256; i++) {
-    sum += (src_ptr[i] * src_ptr[i]);
-  }
+  for (i = 0; i < 256; i++)
+    sum += src_ptr[i] * src_ptr[i];
 
   return sum;
 }
 
-unsigned int vp9_variance64x32_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 64, 32, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 11));
+#define VAR(W, H) \
+unsigned int vp9_variance##W##x##H##_c(const uint8_t *a, int a_stride, \
+                                       const uint8_t *b, int b_stride, \
+                                       unsigned int *sse) { \
+  unsigned int var; \
+  int avg; \
+\
+  variance(a, a_stride, b, b_stride, W, H, &var, &avg); \
+  *sse = var; \
+  return var - (((int64_t)avg * avg) / (W * H)); \
 }
 
-unsigned int vp9_sub_pixel_variance64x32_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 64, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 64, 64, 32, 64, vfilter);
-
-  return vp9_variance64x32(temp2, 64, dst_ptr, dst_pixels_per_line, sse);
+#define SUBPIX_VAR(W, H) \
+unsigned int vp9_sub_pixel_variance##W##x##H##_c( \
+  const uint8_t *src, int  src_stride, \
+  int xoffset, int  yoffset, \
+  const uint8_t *dst, int dst_stride, \
+  unsigned int *sse) { \
+  uint16_t fdata3[(H + 1) * W]; \
+  uint8_t temp2[H * W]; \
+\
+  var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, W, \
+                                    BILINEAR_FILTERS_2TAP(xoffset)); \
+  var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
+                                     BILINEAR_FILTERS_2TAP(yoffset)); \
+\
+  return vp9_variance##W##x##H##_c(temp2, W, dst, dst_stride, sse); \
 }
 
-unsigned int vp9_sub_pixel_avg_variance64x32_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 64 * 64);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 64, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 64, 64, 32, 64, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 64, 32, temp2, 64);
-  return vp9_variance64x32(temp3, 64, dst_ptr, dst_pixels_per_line, sse);
+#define SUBPIX_AVG_VAR(W, H) \
+unsigned int vp9_sub_pixel_avg_variance##W##x##H##_c( \
+  const uint8_t *src, int  src_stride, \
+  int xoffset, int  yoffset, \
+  const uint8_t *dst, int dst_stride, \
+  unsigned int *sse, \
+  const uint8_t *second_pred) { \
+  uint16_t fdata3[(H + 1) * W]; \
+  uint8_t temp2[H * W]; \
+  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, H * W); \
+\
+  var_filter_block2d_bil_first_pass(src, fdata3, src_stride, 1, H + 1, W, \
+                                    BILINEAR_FILTERS_2TAP(xoffset)); \
+  var_filter_block2d_bil_second_pass(fdata3, temp2, W, W, H, W, \
+                                     BILINEAR_FILTERS_2TAP(yoffset)); \
+\
+  vp9_comp_avg_pred(temp3, second_pred, W, H, temp2, W); \
+\
+  return vp9_variance##W##x##H##_c(temp3, W, dst, dst_stride, sse); \
 }
 
-unsigned int vp9_variance32x64_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 32, 64, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 11));
-}
-
-unsigned int vp9_sub_pixel_variance32x64_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 65, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 64, 32, vfilter);
-
-  return vp9_variance32x64(temp2, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance32x64_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 32 * 64);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 65, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 64, 32, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 32, 64, temp2, 32);
-  return vp9_variance32x64(temp3, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_variance32x16_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 32, 16, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 9));
-}
-
-unsigned int vp9_sub_pixel_variance32x16_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 16, 32, vfilter);
-
-  return vp9_variance32x16(temp2, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance32x16_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 32 * 16);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 16, 32, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 32, 16, temp2, 32);
-  return vp9_variance32x16(temp3, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_variance16x32_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 32, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 9));
-}
-
-unsigned int vp9_sub_pixel_variance16x32_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 32, 16, vfilter);
-
-  return vp9_variance16x32(temp2, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance16x32_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 16 * 32);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 32, 16, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 16, 32, temp2, 16);
-  return vp9_variance16x32(temp3, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_variance64x64_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 64, 64, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 12));
-}
-
-unsigned int vp9_variance32x32_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 32, 32, &var, &avg);
-  *sse = var;
-  return (var - (((int64_t)avg * avg) >> 10));
-}
 
 void vp9_get_sse_sum_16x16_c(const uint8_t *src_ptr, int source_stride,
                              const uint8_t *ref_ptr, int ref_stride,
@@ -423,104 +166,12 @@
   variance(src_ptr, source_stride, ref_ptr, ref_stride, 16, 16, sse, sum);
 }
 
-unsigned int vp9_variance16x16_c(const uint8_t *src_ptr,
-                                 int  source_stride,
-                                 const uint8_t *ref_ptr,
-                                 int  recon_stride,
-                                 unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 8));
-}
-
-unsigned int vp9_variance8x16_c(const uint8_t *src_ptr,
-                                int  source_stride,
-                                const uint8_t *ref_ptr,
-                                int  recon_stride,
-                                unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 16, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 7));
-}
-
-unsigned int vp9_variance16x8_c(const uint8_t *src_ptr,
-                                int  source_stride,
-                                const uint8_t *ref_ptr,
-                                int  recon_stride,
-                                unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 8, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 7));
-}
-
 void vp9_get_sse_sum_8x8_c(const uint8_t *src_ptr, int source_stride,
                        const uint8_t *ref_ptr, int ref_stride,
                        unsigned int *sse, int *sum) {
   variance(src_ptr, source_stride, ref_ptr, ref_stride, 8, 8, sse, sum);
 }
 
-unsigned int vp9_variance8x8_c(const uint8_t *src_ptr,
-                               int  source_stride,
-                               const uint8_t *ref_ptr,
-                               int  recon_stride,
-                               unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 8, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 6));
-}
-
-unsigned int vp9_variance8x4_c(const uint8_t *src_ptr,
-                               int  source_stride,
-                               const uint8_t *ref_ptr,
-                               int  recon_stride,
-                               unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 4, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 5));
-}
-
-unsigned int vp9_variance4x8_c(const uint8_t *src_ptr,
-                               int  source_stride,
-                               const uint8_t *ref_ptr,
-                               int  recon_stride,
-                               unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 4, 8, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 5));
-}
-
-unsigned int vp9_variance4x4_c(const uint8_t *src_ptr,
-                               int  source_stride,
-                               const uint8_t *ref_ptr,
-                               int  recon_stride,
-                               unsigned int *sse) {
-  unsigned int var;
-  int avg;
-
-  variance(src_ptr, source_stride, ref_ptr, recon_stride, 4, 4, &var, &avg);
-  *sse = var;
-  return (var - (((unsigned int)avg * avg) >> 4));
-}
-
-
 unsigned int vp9_mse16x16_c(const uint8_t *src_ptr,
                             int  source_stride,
                             const uint8_t *ref_ptr,
@@ -573,532 +224,57 @@
   return var;
 }
 
+VAR(4, 4)
+SUBPIX_VAR(4, 4)
+SUBPIX_AVG_VAR(4, 4)
 
-unsigned int vp9_sub_pixel_variance4x4_c(const uint8_t *src_ptr,
-                                         int  src_pixels_per_line,
-                                         int  xoffset,
-                                         int  yoffset,
-                                         const uint8_t *dst_ptr,
-                                         int dst_pixels_per_line,
-                                         unsigned int *sse) {
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-  uint16_t fdata3[5 * 4];  // Temp data buffer used in filtering
+VAR(4, 8)
+SUBPIX_VAR(4, 8)
+SUBPIX_AVG_VAR(4, 8)
 
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
+VAR(8, 4)
+SUBPIX_VAR(8, 4)
+SUBPIX_AVG_VAR(8, 4)
 
-  // First filter 1d Horizontal
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 5, 4, hfilter);
+VAR(8, 8)
+SUBPIX_VAR(8, 8)
+SUBPIX_AVG_VAR(8, 8)
 
-  // Now filter Verticaly
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 4,  4,  4,  4, vfilter);
+VAR(8, 16)
+SUBPIX_VAR(8, 16)
+SUBPIX_AVG_VAR(8, 16)
 
-  return vp9_variance4x4(temp2, 4, dst_ptr, dst_pixels_per_line, sse);
-}
+VAR(16, 8)
+SUBPIX_VAR(16, 8)
+SUBPIX_AVG_VAR(16, 8)
 
-unsigned int vp9_sub_pixel_avg_variance4x4_c(const uint8_t *src_ptr,
-                                             int  src_pixels_per_line,
-                                             int  xoffset,
-                                             int  yoffset,
-                                             const uint8_t *dst_ptr,
-                                             int dst_pixels_per_line,
-                                             unsigned int *sse,
-                                             const uint8_t *second_pred) {
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 4 * 4);  // compound pred buffer
-  uint16_t fdata3[5 * 4];  // Temp data buffer used in filtering
+VAR(16, 16)
+SUBPIX_VAR(16, 16)
+SUBPIX_AVG_VAR(16, 16)
 
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
+VAR(16, 32)
+SUBPIX_VAR(16, 32)
+SUBPIX_AVG_VAR(16, 32)
 
-  // First filter 1d Horizontal
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 5, 4, hfilter);
+VAR(32, 16)
+SUBPIX_VAR(32, 16)
+SUBPIX_AVG_VAR(32, 16)
 
-  // Now filter Verticaly
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 4,  4,  4,  4, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 4, 4, temp2, 4);
-  return vp9_variance4x4(temp3, 4, dst_ptr, dst_pixels_per_line, sse);
-}
+VAR(32, 32)
+SUBPIX_VAR(32, 32)
+SUBPIX_AVG_VAR(32, 32)
 
-unsigned int vp9_sub_pixel_variance8x8_c(const uint8_t *src_ptr,
-                                         int  src_pixels_per_line,
-                                         int  xoffset,
-                                         int  yoffset,
-                                         const uint8_t *dst_ptr,
-                                         int dst_pixels_per_line,
-                                         unsigned int *sse) {
-  uint16_t fdata3[9 * 8];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
+VAR(32, 64)
+SUBPIX_VAR(32, 64)
+SUBPIX_AVG_VAR(32, 64)
 
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
+VAR(64, 32)
+SUBPIX_VAR(64, 32)
+SUBPIX_AVG_VAR(64, 32)
 
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 8, 8, vfilter);
-
-  return vp9_variance8x8(temp2, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance8x8_c(const uint8_t *src_ptr,
-                                             int  src_pixels_per_line,
-                                             int  xoffset,
-                                             int  yoffset,
-                                             const uint8_t *dst_ptr,
-                                             int dst_pixels_per_line,
-                                             unsigned int *sse,
-                                             const uint8_t *second_pred) {
-  uint16_t fdata3[9 * 8];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 8 * 8);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 8, 8, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 8, 8, temp2, 8);
-  return vp9_variance8x8(temp3, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance16x16_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[17 * 16];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 16, 16, vfilter);
-
-  return vp9_variance16x16(temp2, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance16x16_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[17 * 16];
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 16 * 16);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 16, 16, vfilter);
-
-  vp9_comp_avg_pred(temp3, second_pred, 16, 16, temp2, 16);
-  return vp9_variance16x16(temp3, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance64x64_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 65, 64, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 64, 64, 64, 64, vfilter);
-
-  return vp9_variance64x64(temp2, 64, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance64x64_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[65 * 64];  // Temp data buffer used in filtering
-  uint8_t temp2[68 * 64];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 64 * 64);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 65, 64, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 64, 64, 64, 64, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 64, 64, temp2, 64);
-  return vp9_variance64x64(temp3, 64, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance32x32_c(const uint8_t *src_ptr,
-                                           int  src_pixels_per_line,
-                                           int  xoffset,
-                                           int  yoffset,
-                                           const uint8_t *dst_ptr,
-                                           int dst_pixels_per_line,
-                                           unsigned int *sse) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 32, 32, vfilter);
-
-  return vp9_variance32x32(temp2, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance32x32_c(const uint8_t *src_ptr,
-                                               int  src_pixels_per_line,
-                                               int  xoffset,
-                                               int  yoffset,
-                                               const uint8_t *dst_ptr,
-                                               int dst_pixels_per_line,
-                                               unsigned int *sse,
-                                               const uint8_t *second_pred) {
-  uint16_t fdata3[33 * 32];  // Temp data buffer used in filtering
-  uint8_t temp2[36 * 32];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 32 * 32);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 33, 32, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 32, 32, 32, 32, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 32, 32, temp2, 32);
-  return vp9_variance32x32(temp3, 32, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_variance_halfpixvar16x16_h_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance16x16_c(src_ptr, source_stride, 8, 0,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar32x32_h_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance32x32_c(src_ptr, source_stride, 8, 0,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar64x64_h_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance64x64_c(src_ptr, source_stride, 8, 0,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar16x16_v_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance16x16_c(src_ptr, source_stride, 0, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar32x32_v_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance32x32_c(src_ptr, source_stride, 0, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar64x64_v_c(const uint8_t *src_ptr,
-                                              int  source_stride,
-                                              const uint8_t *ref_ptr,
-                                              int  recon_stride,
-                                              unsigned int *sse) {
-  return vp9_sub_pixel_variance64x64_c(src_ptr, source_stride, 0, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar16x16_hv_c(const uint8_t *src_ptr,
-                                               int  source_stride,
-                                               const uint8_t *ref_ptr,
-                                               int  recon_stride,
-                                               unsigned int *sse) {
-  return vp9_sub_pixel_variance16x16_c(src_ptr, source_stride, 8, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar32x32_hv_c(const uint8_t *src_ptr,
-                                               int  source_stride,
-                                               const uint8_t *ref_ptr,
-                                               int  recon_stride,
-                                               unsigned int *sse) {
-  return vp9_sub_pixel_variance32x32_c(src_ptr, source_stride, 8, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_variance_halfpixvar64x64_hv_c(const uint8_t *src_ptr,
-                                               int  source_stride,
-                                               const uint8_t *ref_ptr,
-                                               int  recon_stride,
-                                               unsigned int *sse) {
-  return vp9_sub_pixel_variance64x64_c(src_ptr, source_stride, 8, 8,
-                                       ref_ptr, recon_stride, sse);
-}
-
-unsigned int vp9_sub_pixel_mse16x16_c(const uint8_t *src_ptr,
-                                      int  src_pixels_per_line,
-                                      int  xoffset,
-                                      int  yoffset,
-                                      const uint8_t *dst_ptr,
-                                      int dst_pixels_per_line,
-                                      unsigned int *sse) {
-  vp9_sub_pixel_variance16x16_c(src_ptr, src_pixels_per_line,
-                                xoffset, yoffset, dst_ptr,
-                                dst_pixels_per_line, sse);
-  return *sse;
-}
-
-unsigned int vp9_sub_pixel_mse32x32_c(const uint8_t *src_ptr,
-                                      int  src_pixels_per_line,
-                                      int  xoffset,
-                                      int  yoffset,
-                                      const uint8_t *dst_ptr,
-                                      int dst_pixels_per_line,
-                                      unsigned int *sse) {
-  vp9_sub_pixel_variance32x32_c(src_ptr, src_pixels_per_line,
-                                xoffset, yoffset, dst_ptr,
-                                dst_pixels_per_line, sse);
-  return *sse;
-}
-
-unsigned int vp9_sub_pixel_mse64x64_c(const uint8_t *src_ptr,
-                                      int  src_pixels_per_line,
-                                      int  xoffset,
-                                      int  yoffset,
-                                      const uint8_t *dst_ptr,
-                                      int dst_pixels_per_line,
-                                      unsigned int *sse) {
-  vp9_sub_pixel_variance64x64_c(src_ptr, src_pixels_per_line,
-                                xoffset, yoffset, dst_ptr,
-                                dst_pixels_per_line, sse);
-  return *sse;
-}
-
-unsigned int vp9_sub_pixel_variance16x8_c(const uint8_t *src_ptr,
-                                          int  src_pixels_per_line,
-                                          int  xoffset,
-                                          int  yoffset,
-                                          const uint8_t *dst_ptr,
-                                          int dst_pixels_per_line,
-                                          unsigned int *sse) {
-  uint16_t fdata3[16 * 9];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 8, 16, vfilter);
-
-  return vp9_variance16x8(temp2, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance16x8_c(const uint8_t *src_ptr,
-                                              int  src_pixels_per_line,
-                                              int  xoffset,
-                                              int  yoffset,
-                                              const uint8_t *dst_ptr,
-                                              int dst_pixels_per_line,
-                                              unsigned int *sse,
-                                              const uint8_t *second_pred) {
-  uint16_t fdata3[16 * 9];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 16 * 8);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 16, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 16, 16, 8, 16, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 16, 8, temp2, 16);
-  return vp9_variance16x8(temp3, 16, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance8x16_c(const uint8_t *src_ptr,
-                                          int  src_pixels_per_line,
-                                          int  xoffset,
-                                          int  yoffset,
-                                          const uint8_t *dst_ptr,
-                                          int dst_pixels_per_line,
-                                          unsigned int *sse) {
-  uint16_t fdata3[9 * 16];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 16, 8, vfilter);
-
-  return vp9_variance8x16(temp2, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance8x16_c(const uint8_t *src_ptr,
-                                              int  src_pixels_per_line,
-                                              int  xoffset,
-                                              int  yoffset,
-                                              const uint8_t *dst_ptr,
-                                              int dst_pixels_per_line,
-                                              unsigned int *sse,
-                                              const uint8_t *second_pred) {
-  uint16_t fdata3[9 * 16];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 8 * 16);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 17, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 16, 8, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 8, 16, temp2, 8);
-  return vp9_variance8x16(temp3, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance8x4_c(const uint8_t *src_ptr,
-                                         int  src_pixels_per_line,
-                                         int  xoffset,
-                                         int  yoffset,
-                                         const uint8_t *dst_ptr,
-                                         int dst_pixels_per_line,
-                                         unsigned int *sse) {
-  uint16_t fdata3[8 * 5];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 5, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 4, 8, vfilter);
-
-  return vp9_variance8x4(temp2, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance8x4_c(const uint8_t *src_ptr,
-                                             int  src_pixels_per_line,
-                                             int  xoffset,
-                                             int  yoffset,
-                                             const uint8_t *dst_ptr,
-                                             int dst_pixels_per_line,
-                                             unsigned int *sse,
-                                             const uint8_t *second_pred) {
-  uint16_t fdata3[8 * 5];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 8 * 4);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 5, 8, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 8, 8, 4, 8, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 8, 4, temp2, 8);
-  return vp9_variance8x4(temp3, 8, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_variance4x8_c(const uint8_t *src_ptr,
-                                         int  src_pixels_per_line,
-                                         int  xoffset,
-                                         int  yoffset,
-                                         const uint8_t *dst_ptr,
-                                         int dst_pixels_per_line,
-                                         unsigned int *sse) {
-  uint16_t fdata3[5 * 8];  // Temp data buffer used in filtering
-  // FIXME(jingning,rbultje): this temp2 buffer probably doesn't need to be
-  // of this big? same issue appears in all other block size settings.
-  uint8_t temp2[20 * 16];
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 4, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 4, 4, 8, 4, vfilter);
-
-  return vp9_variance4x8(temp2, 4, dst_ptr, dst_pixels_per_line, sse);
-}
-
-unsigned int vp9_sub_pixel_avg_variance4x8_c(const uint8_t *src_ptr,
-                                             int  src_pixels_per_line,
-                                             int  xoffset,
-                                             int  yoffset,
-                                             const uint8_t *dst_ptr,
-                                             int dst_pixels_per_line,
-                                             unsigned int *sse,
-                                             const uint8_t *second_pred) {
-  uint16_t fdata3[5 * 8];  // Temp data buffer used in filtering
-  uint8_t temp2[20 * 16];
-  DECLARE_ALIGNED_ARRAY(16, uint8_t, temp3, 4 * 8);  // compound pred buffer
-  const int16_t *hfilter, *vfilter;
-
-  hfilter = BILINEAR_FILTERS_2TAP(xoffset);
-  vfilter = BILINEAR_FILTERS_2TAP(yoffset);
-
-  var_filter_block2d_bil_first_pass(src_ptr, fdata3, src_pixels_per_line,
-                                    1, 9, 4, hfilter);
-  var_filter_block2d_bil_second_pass(fdata3, temp2, 4, 4, 8, 4, vfilter);
-  vp9_comp_avg_pred(temp3, second_pred, 4, 8, temp2, 4);
-  return vp9_variance4x8(temp3, 4, dst_ptr, dst_pixels_per_line, sse);
-}
-
+VAR(64, 64)
+SUBPIX_VAR(64, 64)
+SUBPIX_AVG_VAR(64, 64)
 
 void vp9_comp_avg_pred(uint8_t *comp_pred, const uint8_t *pred, int width,
                        int height, const uint8_t *ref, int ref_stride) {
@@ -1106,9 +282,8 @@
 
   for (i = 0; i < height; i++) {
     for (j = 0; j < width; j++) {
-      int tmp;
-      tmp = pred[j] + ref[j];
-      comp_pred[j] = (tmp + 1) >> 1;
+      const int tmp = pred[j] + ref[j];
+      comp_pred[j] = ROUND_POWER_OF_TWO(tmp, 1);
     }
     comp_pred += width;
     pred += width;
diff --git a/vp9/encoder/vp9_variance.h b/vp9/encoder/vp9_variance.h
index 62e20dc..c47fe13 100644
--- a/vp9/encoder/vp9_variance.h
+++ b/vp9/encoder/vp9_variance.h
@@ -17,14 +17,10 @@
 extern "C" {
 #endif
 
-void variance(const uint8_t *src_ptr,
-              int  source_stride,
-              const uint8_t *ref_ptr,
-              int  recon_stride,
-              int  w,
-              int  h,
-              unsigned int *sse,
-              int *sum);
+void variance(const uint8_t *a, int a_stride,
+              const uint8_t *b, int b_stride,
+              int  w, int  h,
+              unsigned int *sse, int *sum);
 
 typedef unsigned int(*vp9_sad_fn_t)(const uint8_t *src_ptr,
                                     int source_stride,
@@ -45,12 +41,6 @@
                                    int  ref_stride,
                                    unsigned int *sad_array);
 
-typedef void (*vp9_sad_multi1_fn_t)(const uint8_t *src_ptr,
-                                    int source_stride,
-                                    const uint8_t *ref_ptr,
-                                    int  ref_stride,
-                                    unsigned int *sad_array);
-
 typedef void (*vp9_sad_multi_d_fn_t)(const uint8_t *src_ptr,
                                      int source_stride,
                                      const uint8_t* const ref_ptr[],
@@ -79,24 +69,14 @@
                                                    unsigned int *sse,
                                                    const uint8_t *second_pred);
 
-typedef unsigned int (*vp9_getmbss_fn_t)(const short *);
-
-typedef unsigned int (*vp9_get16x16prederror_fn_t)(const uint8_t *src_ptr,
-                                                   int source_stride,
-                                                   const uint8_t *ref_ptr,
-                                                   int  ref_stride);
-
 typedef struct vp9_variance_vtable {
   vp9_sad_fn_t               sdf;
   vp9_sad_avg_fn_t           sdaf;
   vp9_variance_fn_t          vf;
   vp9_subpixvariance_fn_t    svf;
   vp9_subp_avg_variance_fn_t svaf;
-  vp9_variance_fn_t          svf_halfpix_h;
-  vp9_variance_fn_t          svf_halfpix_v;
-  vp9_variance_fn_t          svf_halfpix_hv;
   vp9_sad_multi_fn_t         sdx3f;
-  vp9_sad_multi1_fn_t        sdx8f;
+  vp9_sad_multi_fn_t         sdx8f;
   vp9_sad_multi_d_fn_t       sdx4df;
 } vp9_variance_fn_ptr_t;
 
diff --git a/vp9/encoder/x86/vp9_dct_ssse3.asm b/vp9/encoder/x86/vp9_dct_ssse3.asm
new file mode 100644
index 0000000..1400071
--- /dev/null
+++ b/vp9/encoder/x86/vp9_dct_ssse3.asm
@@ -0,0 +1,174 @@
+;
+;  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+;
+;  Use of this source code is governed by a BSD-style license
+;  that can be found in the LICENSE file in the root of the source
+;  tree. An additional intellectual property rights grant can be found
+;  in the file PATENTS.  All contributing project authors may
+;  be found in the AUTHORS file in the root of the source tree.
+;
+%include "third_party/x86inc/x86inc.asm"
+
+; This file provides SSSE3 version of the forward transformation. Part
+; of the macro definitions are originally derived from ffmpeg project.
+; The current version applies to x86 64-bit only.
+
+SECTION_RODATA
+
+pw_11585x2: times 8 dw 23170
+pd_8192:    times 4 dd 8192
+
+%macro TRANSFORM_COEFFS 2
+pw_%1_%2:   dw  %1,  %2,  %1,  %2,  %1,  %2,  %1,  %2
+pw_%2_m%1:  dw  %2, -%1,  %2, -%1,  %2, -%1,  %2, -%1
+%endmacro
+
+TRANSFORM_COEFFS 15137,   6270
+TRANSFORM_COEFFS 16069,   3196
+TRANSFORM_COEFFS  9102,  13623
+
+SECTION .text
+
+%if ARCH_X86_64
+%macro SUM_SUB 3
+  psubw  m%3, m%1, m%2
+  paddw  m%1, m%2
+  SWAP    %2, %3
+%endmacro
+
+; butterfly operation
+%macro MUL_ADD_2X 6 ; dst1, dst2, src, round, coefs1, coefs2
+  pmaddwd            m%1, m%3, %5
+  pmaddwd            m%2, m%3, %6
+  paddd              m%1,  %4
+  paddd              m%2,  %4
+  psrad              m%1,  14
+  psrad              m%2,  14
+%endmacro
+
+%macro BUTTERFLY_4X 7 ; dst1, dst2, coef1, coef2, round, tmp1, tmp2
+  punpckhwd          m%6, m%2, m%1
+  MUL_ADD_2X         %7,  %6,  %6,  %5, [pw_%4_%3], [pw_%3_m%4]
+  punpcklwd          m%2, m%1
+  MUL_ADD_2X         %1,  %2,  %2,  %5, [pw_%4_%3], [pw_%3_m%4]
+  packssdw           m%1, m%7
+  packssdw           m%2, m%6
+%endmacro
+
+; matrix transpose
+%macro INTERLEAVE_2X 4
+  punpckh%1          m%4, m%2, m%3
+  punpckl%1          m%2, m%3
+  SWAP               %3,  %4
+%endmacro
+
+%macro TRANSPOSE8X8 9
+  INTERLEAVE_2X  wd, %1, %2, %9
+  INTERLEAVE_2X  wd, %3, %4, %9
+  INTERLEAVE_2X  wd, %5, %6, %9
+  INTERLEAVE_2X  wd, %7, %8, %9
+
+  INTERLEAVE_2X  dq, %1, %3, %9
+  INTERLEAVE_2X  dq, %2, %4, %9
+  INTERLEAVE_2X  dq, %5, %7, %9
+  INTERLEAVE_2X  dq, %6, %8, %9
+
+  INTERLEAVE_2X  qdq, %1, %5, %9
+  INTERLEAVE_2X  qdq, %3, %7, %9
+  INTERLEAVE_2X  qdq, %2, %6, %9
+  INTERLEAVE_2X  qdq, %4, %8, %9
+
+  SWAP  %2, %5
+  SWAP  %4, %7
+%endmacro
+
+; 1D forward 8x8 DCT transform
+%macro FDCT8_1D 0
+  SUM_SUB            0,  7,  9
+  SUM_SUB            1,  6,  9
+  SUM_SUB            2,  5,  9
+  SUM_SUB            3,  4,  9
+
+  SUM_SUB            0,  3,  9
+  SUM_SUB            1,  2,  9
+  SUM_SUB            6,  5,  9
+  SUM_SUB            0,  1,  9
+
+  BUTTERFLY_4X       2,  3,  6270,  15137,  m8,  9,  10
+
+  pmulhrsw           m6, m12
+  pmulhrsw           m5, m12
+  pmulhrsw           m0, m12
+  pmulhrsw           m1, m12
+
+  SUM_SUB            4,  5,  9
+  SUM_SUB            7,  6,  9
+  BUTTERFLY_4X       4,  7,  3196,  16069,  m8,  9,  10
+  BUTTERFLY_4X       5,  6,  13623,  9102,  m8,  9,  10
+  SWAP               1,  4
+  SWAP               3,  6
+%endmacro
+
+%macro DIVIDE_ROUND_2X 4 ; dst1, dst2, tmp1, tmp2
+  psraw              m%3, m%1, 15
+  psraw              m%4, m%2, 15
+  psubw              m%1, m%3
+  psubw              m%2, m%4
+  psraw              m%1, 1
+  psraw              m%2, 1
+%endmacro
+
+INIT_XMM ssse3
+cglobal fdct8x8, 3, 5, 13, input, output, stride
+
+  mova               m8, [pd_8192]
+  mova              m12, [pw_11585x2]
+  pxor              m11, m11
+
+  lea                r3, [2 * strideq]
+  lea                r4, [4 * strideq]
+  mova               m0, [inputq]
+  mova               m1, [inputq + r3]
+  lea                inputq, [inputq + r4]
+  mova               m2, [inputq]
+  mova               m3, [inputq + r3]
+  lea                inputq, [inputq + r4]
+  mova               m4, [inputq]
+  mova               m5, [inputq + r3]
+  lea                inputq, [inputq + r4]
+  mova               m6, [inputq]
+  mova               m7, [inputq + r3]
+
+  ; left shift by 2 to increase forward transformation precision
+  psllw              m0, 2
+  psllw              m1, 2
+  psllw              m2, 2
+  psllw              m3, 2
+  psllw              m4, 2
+  psllw              m5, 2
+  psllw              m6, 2
+  psllw              m7, 2
+
+  ; column transform
+  FDCT8_1D
+  TRANSPOSE8X8 0, 1, 2, 3, 4, 5, 6, 7, 9
+
+  FDCT8_1D
+  TRANSPOSE8X8 0, 1, 2, 3, 4, 5, 6, 7, 9
+
+  DIVIDE_ROUND_2X   0, 1, 9, 10
+  DIVIDE_ROUND_2X   2, 3, 9, 10
+  DIVIDE_ROUND_2X   4, 5, 9, 10
+  DIVIDE_ROUND_2X   6, 7, 9, 10
+
+  mova              [outputq +   0], m0
+  mova              [outputq +  16], m1
+  mova              [outputq +  32], m2
+  mova              [outputq +  48], m3
+  mova              [outputq +  64], m4
+  mova              [outputq +  80], m5
+  mova              [outputq +  96], m6
+  mova              [outputq + 112], m7
+
+  RET
+%endif
diff --git a/vp9/encoder/x86/vp9_mcomp_x86.h b/vp9/encoder/x86/vp9_mcomp_x86.h
deleted file mode 100644
index c15039a..0000000
--- a/vp9/encoder/x86/vp9_mcomp_x86.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-
-#ifndef VP9_ENCODER_X86_VP9_MCOMP_X86_H_
-#define VP9_ENCODER_X86_VP9_MCOMP_X86_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if HAVE_SSE3
-#if !CONFIG_RUNTIME_CPU_DETECT
-
-#undef  vp9_search_full_search
-#define vp9_search_full_search vp9_full_search_sadx3
-
-#undef  vp9_search_refining_search
-#define vp9_search_refining_search vp9_refining_search_sadx4
-
-#undef  vp9_search_diamond_search
-#define vp9_search_diamond_search vp9_diamond_search_sadx4
-
-#endif
-#endif
-
-#if HAVE_SSE4_1
-#if !CONFIG_RUNTIME_CPU_DETECT
-
-#undef  vp9_search_full_search
-#define vp9_search_full_search vp9_full_search_sadx8
-
-#endif
-#endif
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // VP9_ENCODER_X86_VP9_MCOMP_X86_H_
-
diff --git a/vp9/encoder/x86/vp9_subpel_variance_impl_sse2.asm b/vp9/encoder/x86/vp9_subpel_variance_impl_sse2.asm
deleted file mode 100644
index 2ecc23e..0000000
--- a/vp9/encoder/x86/vp9_subpel_variance_impl_sse2.asm
+++ /dev/null
@@ -1,337 +0,0 @@
-;
-;  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-;
-;  Use of this source code is governed by a BSD-style license
-;  that can be found in the LICENSE file in the root of the source
-;  tree. An additional intellectual property rights grant can be found
-;  in the file PATENTS.  All contributing project authors may
-;  be found in the AUTHORS file in the root of the source tree.
-;
-
-%include "vpx_ports/x86_abi_support.asm"
-
-;void vp9_half_horiz_vert_variance16x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_horiz_vert_variance16x_h_sse2) PRIVATE
-sym(vp9_half_horiz_vert_variance16x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0) ;ref_ptr              ;
-
-        mov             rdi,            arg(2) ;src_ptr              ;
-        movsxd          rcx,            dword ptr arg(4) ;Height              ;
-        movsxd          rax,            dword ptr arg(1) ;ref_pixels_per_line
-        movsxd          rdx,            dword ptr arg(3)    ;src_pixels_per_line
-
-        pxor            xmm0,           xmm0                ;
-
-        movdqu          xmm5,           XMMWORD PTR [rsi]
-        movdqu          xmm3,           XMMWORD PTR [rsi+1]
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3) horizontal line 1
-
-        lea             rsi,            [rsi + rax]
-
-.half_horiz_vert_variance16x_h_1:
-        movdqu          xmm1,           XMMWORD PTR [rsi]     ;
-        movdqu          xmm2,           XMMWORD PTR [rsi+1]   ;
-        pavgb           xmm1,           xmm2                ;  xmm1 = avg(xmm1,xmm3) horizontal line i+1
-
-        pavgb           xmm5,           xmm1                ;  xmm = vertical average of the above
-
-        movdqa          xmm4,           xmm5
-        punpcklbw       xmm5,           xmm0                ;  xmm5 = words of above
-        punpckhbw       xmm4,           xmm0
-
-        movq            xmm3,           QWORD PTR [rdi]     ;  xmm3 = d0,d1,d2..d7
-        punpcklbw       xmm3,           xmm0                ;  xmm3 = words of above
-        psubw           xmm5,           xmm3                ;  xmm5 -= xmm3
-
-        movq            xmm3,           QWORD PTR [rdi+8]
-        punpcklbw       xmm3,           xmm0
-        psubw           xmm4,           xmm3
-
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        paddw           xmm6,           xmm4
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        pmaddwd         xmm4,           xmm4
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-        paddd           xmm7,           xmm4
-
-        movdqa          xmm5,           xmm1                ;  save xmm1 for use on the next row
-
-        lea             rsi,            [rsi + rax]
-        lea             rdi,            [rdi + rdx]
-
-        sub             rcx,            1                   ;
-        jnz             .half_horiz_vert_variance16x_h_1    ;
-
-        pxor        xmm1,           xmm1
-        pxor        xmm5,           xmm5
-
-        punpcklwd   xmm0,           xmm6
-        punpckhwd   xmm1,           xmm6
-        psrad       xmm0,           16
-        psrad       xmm1,           16
-        paddd       xmm0,           xmm1
-        movdqa      xmm1,           xmm0
-
-        movdqa      xmm6,           xmm7
-        punpckldq   xmm6,           xmm5
-        punpckhdq   xmm7,           xmm5
-        paddd       xmm6,           xmm7
-
-        punpckldq   xmm0,           xmm5
-        punpckhdq   xmm1,           xmm5
-        paddd       xmm0,           xmm1
-
-        movdqa      xmm7,           xmm6
-        movdqa      xmm1,           xmm0
-
-        psrldq      xmm7,           8
-        psrldq      xmm1,           8
-
-        paddd       xmm6,           xmm7
-        paddd       xmm0,           xmm1
-
-        mov         rsi,            arg(5) ;[Sum]
-        mov         rdi,            arg(6) ;[SSE]
-
-        movd        [rsi],       xmm0
-        movd        [rdi],       xmm6
-
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
-
-;void vp9_half_vert_variance16x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_vert_variance16x_h_sse2) PRIVATE
-sym(vp9_half_vert_variance16x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0)              ;ref_ptr
-
-        mov             rdi,            arg(2)              ;src_ptr
-        movsxd          rcx,            dword ptr arg(4)    ;Height
-        movsxd          rax,            dword ptr arg(1)    ;ref_pixels_per_line
-        movsxd          rdx,            dword ptr arg(3)    ;src_pixels_per_line
-
-        movdqu          xmm5,           XMMWORD PTR [rsi]
-        lea             rsi,            [rsi + rax          ]
-        pxor            xmm0,           xmm0
-
-.half_vert_variance16x_h_1:
-        movdqu          xmm3,           XMMWORD PTR [rsi]
-
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3)
-        movdqa          xmm4,           xmm5
-        punpcklbw       xmm5,           xmm0
-        punpckhbw       xmm4,           xmm0
-
-        movq            xmm2,           QWORD PTR [rdi]
-        punpcklbw       xmm2,           xmm0
-        psubw           xmm5,           xmm2
-        movq            xmm2,           QWORD PTR [rdi+8]
-        punpcklbw       xmm2,           xmm0
-        psubw           xmm4,           xmm2
-
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        paddw           xmm6,           xmm4
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        pmaddwd         xmm4,           xmm4
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-        paddd           xmm7,           xmm4
-
-        movdqa          xmm5,           xmm3
-
-        lea             rsi,            [rsi + rax]
-        lea             rdi,            [rdi + rdx]
-
-        sub             rcx,            1
-        jnz             .half_vert_variance16x_h_1
-
-        pxor        xmm1,           xmm1
-        pxor        xmm5,           xmm5
-
-        punpcklwd   xmm0,           xmm6
-        punpckhwd   xmm1,           xmm6
-        psrad       xmm0,           16
-        psrad       xmm1,           16
-        paddd       xmm0,           xmm1
-        movdqa      xmm1,           xmm0
-
-        movdqa      xmm6,           xmm7
-        punpckldq   xmm6,           xmm5
-        punpckhdq   xmm7,           xmm5
-        paddd       xmm6,           xmm7
-
-        punpckldq   xmm0,           xmm5
-        punpckhdq   xmm1,           xmm5
-        paddd       xmm0,           xmm1
-
-        movdqa      xmm7,           xmm6
-        movdqa      xmm1,           xmm0
-
-        psrldq      xmm7,           8
-        psrldq      xmm1,           8
-
-        paddd       xmm6,           xmm7
-        paddd       xmm0,           xmm1
-
-        mov         rsi,            arg(5) ;[Sum]
-        mov         rdi,            arg(6) ;[SSE]
-
-        movd        [rsi],       xmm0
-        movd        [rdi],       xmm6
-
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
-
-;void vp9_half_horiz_variance16x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_horiz_variance16x_h_sse2) PRIVATE
-sym(vp9_half_horiz_variance16x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0) ;ref_ptr              ;
-
-        mov             rdi,            arg(2) ;src_ptr              ;
-        movsxd          rcx,            dword ptr arg(4) ;Height              ;
-        movsxd          rax,            dword ptr arg(1) ;ref_pixels_per_line
-        movsxd          rdx,            dword ptr arg(3)    ;src_pixels_per_line
-
-        pxor            xmm0,           xmm0                ;
-
-.half_horiz_variance16x_h_1:
-        movdqu          xmm5,           XMMWORD PTR [rsi]     ;  xmm5 = s0,s1,s2..s15
-        movdqu          xmm3,           XMMWORD PTR [rsi+1]   ;  xmm3 = s1,s2,s3..s16
-
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3)
-        movdqa          xmm1,           xmm5
-        punpcklbw       xmm5,           xmm0                ;  xmm5 = words of above
-        punpckhbw       xmm1,           xmm0
-
-        movq            xmm3,           QWORD PTR [rdi]     ;  xmm3 = d0,d1,d2..d7
-        punpcklbw       xmm3,           xmm0                ;  xmm3 = words of above
-        movq            xmm2,           QWORD PTR [rdi+8]
-        punpcklbw       xmm2,           xmm0
-
-        psubw           xmm5,           xmm3                ;  xmm5 -= xmm3
-        psubw           xmm1,           xmm2
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        paddw           xmm6,           xmm1
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        pmaddwd         xmm1,           xmm1
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-        paddd           xmm7,           xmm1
-
-        lea             rsi,            [rsi + rax]
-        lea             rdi,            [rdi + rdx]
-
-        sub             rcx,            1                   ;
-        jnz             .half_horiz_variance16x_h_1         ;
-
-        pxor        xmm1,           xmm1
-        pxor        xmm5,           xmm5
-
-        punpcklwd   xmm0,           xmm6
-        punpckhwd   xmm1,           xmm6
-        psrad       xmm0,           16
-        psrad       xmm1,           16
-        paddd       xmm0,           xmm1
-        movdqa      xmm1,           xmm0
-
-        movdqa      xmm6,           xmm7
-        punpckldq   xmm6,           xmm5
-        punpckhdq   xmm7,           xmm5
-        paddd       xmm6,           xmm7
-
-        punpckldq   xmm0,           xmm5
-        punpckhdq   xmm1,           xmm5
-        paddd       xmm0,           xmm1
-
-        movdqa      xmm7,           xmm6
-        movdqa      xmm1,           xmm0
-
-        psrldq      xmm7,           8
-        psrldq      xmm1,           8
-
-        paddd       xmm6,           xmm7
-        paddd       xmm0,           xmm1
-
-        mov         rsi,            arg(5) ;[Sum]
-        mov         rdi,            arg(6) ;[SSE]
-
-        movd        [rsi],       xmm0
-        movd        [rdi],       xmm6
-
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
diff --git a/vp9/encoder/x86/vp9_variance_impl_sse2.asm b/vp9/encoder/x86/vp9_variance_impl_sse2.asm
index 2c50881..4830412 100644
--- a/vp9/encoder/x86/vp9_variance_impl_sse2.asm
+++ b/vp9/encoder/x86/vp9_variance_impl_sse2.asm
@@ -398,337 +398,4 @@
     pop         rbp
     ret
 
-;void vp9_half_horiz_vert_variance8x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_horiz_vert_variance8x_h_sse2) PRIVATE
-sym(vp9_half_horiz_vert_variance8x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-%if ABI_IS_32BIT=0
-    movsxd          r8, dword ptr arg(1) ;ref_pixels_per_line
-    movsxd          r9, dword ptr arg(3) ;src_pixels_per_line
-%endif
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0) ;ref_ptr              ;
-
-        mov             rdi,            arg(2) ;src_ptr              ;
-        movsxd          rcx,            dword ptr arg(4) ;Height              ;
-        movsxd          rax,            dword ptr arg(1) ;ref_pixels_per_line
-
-        pxor            xmm0,           xmm0                ;
-
-        movq            xmm5,           QWORD PTR [rsi]     ;  xmm5 = s0,s1,s2..s8
-        movq            xmm3,           QWORD PTR [rsi+1]   ;  xmm3 = s1,s2,s3..s9
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3) horizontal line 1
-
-%if ABI_IS_32BIT
-        add             rsi,            dword ptr arg(1) ;ref_pixels_per_line    ;  next source
-%else
-        add             rsi, r8
-%endif
-
-.half_horiz_vert_variance8x_h_1:
-
-        movq            xmm1,           QWORD PTR [rsi]     ;
-        movq            xmm2,           QWORD PTR [rsi+1]   ;
-        pavgb           xmm1,           xmm2                ;  xmm1 = avg(xmm1,xmm3) horizontal line i+1
-
-        pavgb           xmm5,           xmm1                ;  xmm = vertical average of the above
-        punpcklbw       xmm5,           xmm0                ;  xmm5 = words of above
-
-        movq            xmm3,           QWORD PTR [rdi]     ;  xmm3 = d0,d1,d2..d8
-        punpcklbw       xmm3,           xmm0                ;  xmm3 = words of above
-
-        psubw           xmm5,           xmm3                ;  xmm5 -= xmm3
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-
-        movdqa          xmm5,           xmm1                ;  save xmm1 for use on the next row
-
-%if ABI_IS_32BIT
-        add             esi,            dword ptr arg(1) ;ref_pixels_per_line    ;  next source
-        add             edi,            dword ptr arg(3) ;src_pixels_per_line    ;  next destination
-%else
-        add             rsi, r8
-        add             rdi, r9
-%endif
-
-        sub             rcx,            1                   ;
-        jnz             .half_horiz_vert_variance8x_h_1     ;
-
-        movdq2q         mm6,            xmm6                ;
-        movdq2q         mm7,            xmm7                ;
-
-        psrldq          xmm6,           8
-        psrldq          xmm7,           8
-
-        movdq2q         mm2,            xmm6
-        movdq2q         mm3,            xmm7
-
-        paddw           mm6,            mm2
-        paddd           mm7,            mm3
-
-        pxor            mm3,            mm3                 ;
-        pxor            mm2,            mm2                 ;
-
-        punpcklwd       mm2,            mm6                 ;
-        punpckhwd       mm3,            mm6                 ;
-
-        paddd           mm2,            mm3                 ;
-        movq            mm6,            mm2                 ;
-
-        psrlq           mm6,            32                  ;
-        paddd           mm2,            mm6                 ;
-
-        psrad           mm2,            16                  ;
-        movq            mm4,            mm7                 ;
-
-        psrlq           mm4,            32                  ;
-        paddd           mm4,            mm7                 ;
-
-        mov             rsi,            arg(5) ; sum
-        mov             rdi,            arg(6) ; sumsquared
-
-        movd            [rsi],          mm2                 ;
-        movd            [rdi],          mm4                 ;
-
-
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
-
-;void vp9_half_vert_variance8x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_vert_variance8x_h_sse2) PRIVATE
-sym(vp9_half_vert_variance8x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-%if ABI_IS_32BIT=0
-    movsxd          r8, dword ptr arg(1) ;ref_pixels_per_line
-    movsxd          r9, dword ptr arg(3) ;src_pixels_per_line
-%endif
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0) ;ref_ptr              ;
-
-        mov             rdi,            arg(2) ;src_ptr              ;
-        movsxd          rcx,            dword ptr arg(4) ;Height              ;
-        movsxd          rax,            dword ptr arg(1) ;ref_pixels_per_line
-
-        pxor            xmm0,           xmm0                ;
-.half_vert_variance8x_h_1:
-        movq            xmm5,           QWORD PTR [rsi]     ;  xmm5 = s0,s1,s2..s8
-        movq            xmm3,           QWORD PTR [rsi+rax] ;  xmm3 = s1,s2,s3..s9
-
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3)
-        punpcklbw       xmm5,           xmm0                ;  xmm5 = words of above
-
-        movq            xmm3,           QWORD PTR [rdi]     ;  xmm3 = d0,d1,d2..d8
-        punpcklbw       xmm3,           xmm0                ;  xmm3 = words of above
-
-        psubw           xmm5,           xmm3                ;  xmm5 -= xmm3
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-
-%if ABI_IS_32BIT
-        add             esi,            dword ptr arg(1) ;ref_pixels_per_line    ;  next source
-        add             edi,            dword ptr arg(3) ;src_pixels_per_line    ;  next destination
-%else
-        add             rsi, r8
-        add             rdi, r9
-%endif
-
-        sub             rcx,            1                   ;
-        jnz             .half_vert_variance8x_h_1          ;
-
-        movdq2q         mm6,            xmm6                ;
-        movdq2q         mm7,            xmm7                ;
-
-        psrldq          xmm6,           8
-        psrldq          xmm7,           8
-
-        movdq2q         mm2,            xmm6
-        movdq2q         mm3,            xmm7
-
-        paddw           mm6,            mm2
-        paddd           mm7,            mm3
-
-        pxor            mm3,            mm3                 ;
-        pxor            mm2,            mm2                 ;
-
-        punpcklwd       mm2,            mm6                 ;
-        punpckhwd       mm3,            mm6                 ;
-
-        paddd           mm2,            mm3                 ;
-        movq            mm6,            mm2                 ;
-
-        psrlq           mm6,            32                  ;
-        paddd           mm2,            mm6                 ;
-
-        psrad           mm2,            16                  ;
-        movq            mm4,            mm7                 ;
-
-        psrlq           mm4,            32                  ;
-        paddd           mm4,            mm7                 ;
-
-        mov             rsi,            arg(5) ; sum
-        mov             rdi,            arg(6) ; sumsquared
-
-        movd            [rsi],          mm2                 ;
-        movd            [rdi],          mm4                 ;
-
-
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
-
-
-;void vp9_half_horiz_variance8x_h_sse2
-;(
-;    unsigned char *ref_ptr,
-;    int ref_pixels_per_line,
-;    unsigned char *src_ptr,
-;    int src_pixels_per_line,
-;    unsigned int Height,
-;    int *sum,
-;    unsigned int *sumsquared
-;)
-global sym(vp9_half_horiz_variance8x_h_sse2) PRIVATE
-sym(vp9_half_horiz_variance8x_h_sse2):
-    push        rbp
-    mov         rbp, rsp
-    SHADOW_ARGS_TO_STACK 7
-    SAVE_XMM 7
-    GET_GOT     rbx
-    push rsi
-    push rdi
-    ; end prolog
-
-%if ABI_IS_32BIT=0
-    movsxd          r8, dword ptr arg(1) ;ref_pixels_per_line
-    movsxd          r9, dword ptr arg(3) ;src_pixels_per_line
-%endif
-
-        pxor            xmm6,           xmm6                ;  error accumulator
-        pxor            xmm7,           xmm7                ;  sse eaccumulator
-        mov             rsi,            arg(0) ;ref_ptr              ;
-
-        mov             rdi,            arg(2) ;src_ptr              ;
-        movsxd          rcx,            dword ptr arg(4) ;Height              ;
-
-        pxor            xmm0,           xmm0                ;
-.half_horiz_variance8x_h_1:
-        movq            xmm5,           QWORD PTR [rsi]     ;  xmm5 = s0,s1,s2..s8
-        movq            xmm3,           QWORD PTR [rsi+1]   ;  xmm3 = s1,s2,s3..s9
-
-        pavgb           xmm5,           xmm3                ;  xmm5 = avg(xmm1,xmm3)
-        punpcklbw       xmm5,           xmm0                ;  xmm5 = words of above
-
-        movq            xmm3,           QWORD PTR [rdi]     ;  xmm3 = d0,d1,d2..d8
-        punpcklbw       xmm3,           xmm0                ;  xmm3 = words of above
-
-        psubw           xmm5,           xmm3                ;  xmm5 -= xmm3
-        paddw           xmm6,           xmm5                ;  xmm6 += accumulated column differences
-        pmaddwd         xmm5,           xmm5                ;  xmm5 *= xmm5
-        paddd           xmm7,           xmm5                ;  xmm7 += accumulated square column differences
-
-%if ABI_IS_32BIT
-        add             esi,            dword ptr arg(1) ;ref_pixels_per_line    ;  next source
-        add             edi,            dword ptr arg(3) ;src_pixels_per_line    ;  next destination
-%else
-        add             rsi, r8
-        add             rdi, r9
-%endif
-        sub             rcx,            1                   ;
-        jnz             .half_horiz_variance8x_h_1          ;
-
-        movdq2q         mm6,            xmm6                ;
-        movdq2q         mm7,            xmm7                ;
-
-        psrldq          xmm6,           8
-        psrldq          xmm7,           8
-
-        movdq2q         mm2,            xmm6
-        movdq2q         mm3,            xmm7
-
-        paddw           mm6,            mm2
-        paddd           mm7,            mm3
-
-        pxor            mm3,            mm3                 ;
-        pxor            mm2,            mm2                 ;
-
-        punpcklwd       mm2,            mm6                 ;
-        punpckhwd       mm3,            mm6                 ;
-
-        paddd           mm2,            mm3                 ;
-        movq            mm6,            mm2                 ;
-
-        psrlq           mm6,            32                  ;
-        paddd           mm2,            mm6                 ;
-
-        psrad           mm2,            16                  ;
-        movq            mm4,            mm7                 ;
-
-        psrlq           mm4,            32                  ;
-        paddd           mm4,            mm7                 ;
-
-        mov             rsi,            arg(5) ; sum
-        mov             rdi,            arg(6) ; sumsquared
-
-        movd            [rsi],          mm2                 ;
-        movd            [rdi],          mm4                 ;
-
 
-    ; begin epilog
-    pop rdi
-    pop rsi
-    RESTORE_GOT
-    RESTORE_XMM
-    UNSHADOW_ARGS
-    pop         rbp
-    ret
diff --git a/vp9/encoder/x86/vp9_variance_sse2.c b/vp9/encoder/x86/vp9_variance_sse2.c
index 9e65694..41f2259 100644
--- a/vp9/encoder/x86/vp9_variance_sse2.c
+++ b/vp9/encoder/x86/vp9_variance_sse2.c
@@ -42,66 +42,6 @@
   unsigned int *SSE,
   int *Sum
 );
-void vp9_half_horiz_vert_variance8x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
-void vp9_half_horiz_vert_variance16x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
-void vp9_half_horiz_variance8x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
-void vp9_half_horiz_variance16x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
-void vp9_half_vert_variance8x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
-void vp9_half_vert_variance16x_h_sse2
-(
-  const unsigned char *ref_ptr,
-  int ref_pixels_per_line,
-  const unsigned char *src_ptr,
-  int src_pixels_per_line,
-  unsigned int Height,
-  int *sum,
-  unsigned int *sumsquared
-);
 
 typedef unsigned int (*get_var_sse2) (
   const unsigned char *src_ptr,
@@ -494,58 +434,3 @@
 
 #undef FNS
 #undef FN
-
-unsigned int vp9_variance_halfpixvar16x16_h_sse2(
-  const unsigned char *src_ptr,
-  int  src_pixels_per_line,
-  const unsigned char *dst_ptr,
-  int  dst_pixels_per_line,
-  unsigned int *sse) {
-  int xsum0;
-  unsigned int xxsum0;
-
-  vp9_half_horiz_variance16x_h_sse2(
-    src_ptr, src_pixels_per_line,
-    dst_ptr, dst_pixels_per_line, 16,
-    &xsum0, &xxsum0);
-
-  *sse = xxsum0;
-  return (xxsum0 - (((unsigned int)xsum0 * xsum0) >> 8));
-}
-
-
-unsigned int vp9_variance_halfpixvar16x16_v_sse2(
-  const unsigned char *src_ptr,
-  int  src_pixels_per_line,
-  const unsigned char *dst_ptr,
-  int  dst_pixels_per_line,
-  unsigned int *sse) {
-  int xsum0;
-  unsigned int xxsum0;
-  vp9_half_vert_variance16x_h_sse2(
-    src_ptr, src_pixels_per_line,
-    dst_ptr, dst_pixels_per_line, 16,
-    &xsum0, &xxsum0);
-
-  *sse = xxsum0;
-  return (xxsum0 - (((unsigned int)xsum0 * xsum0) >> 8));
-}
-
-
-unsigned int vp9_variance_halfpixvar16x16_hv_sse2(
-  const unsigned char *src_ptr,
-  int  src_pixels_per_line,
-  const unsigned char *dst_ptr,
-  int  dst_pixels_per_line,
-  unsigned int *sse) {
-  int xsum0;
-  unsigned int xxsum0;
-
-  vp9_half_horiz_vert_variance16x_h_sse2(
-    src_ptr, src_pixels_per_line,
-    dst_ptr, dst_pixels_per_line, 16,
-    &xsum0, &xxsum0);
-
-  *sse = xxsum0;
-  return (xxsum0 - (((unsigned int)xsum0 * xsum0) >> 8));
-}
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 0623ad1..449e7d8 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -14,7 +14,7 @@
 #include "vpx/vpx_codec.h"
 #include "vpx/internal/vpx_codec_internal.h"
 #include "./vpx_version.h"
-#include "vp9/encoder/vp9_onyx_int.h"
+#include "vp9/encoder/vp9_encoder.h"
 #include "vpx/vp8cx.h"
 #include "vp9/encoder/vp9_firstpass.h"
 #include "vp9/vp9_iface_common.h"
@@ -77,7 +77,7 @@
   vpx_codec_priv_t        base;
   vpx_codec_enc_cfg_t     cfg;
   struct vp9_extracfg     extra_cfg;
-  VP9_CONFIG              oxcf;
+  VP9EncoderConfig        oxcf;
   VP9_COMP               *cpi;
   unsigned char          *cx_data;
   size_t                  cx_data_sz;
@@ -168,6 +168,11 @@
   RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
   RANGE_CHECK(cfg,        g_pass,         VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);
 
+  if (cfg->rc_resize_allowed == 1) {
+    RANGE_CHECK(cfg, rc_scaled_width, 1, cfg->g_w);
+    RANGE_CHECK(cfg, rc_scaled_height, 1, cfg->g_h);
+  }
+
   RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
   RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
   if (cfg->ts_number_layers > 1) {
@@ -182,7 +187,7 @@
         ERROR("ts_rate_decimator factors are not powers of 2");
   }
 
-  // VP8 does not support a lower bound on the keyframe interval in
+  // VP9 does not support a lower bound on the keyframe interval in
   // automatic keyframe placement mode.
   if (cfg->kf_mode != VPX_KF_DISABLED &&
       cfg->kf_min_dist != cfg->kf_max_dist &&
@@ -286,7 +291,7 @@
 
 
 static vpx_codec_err_t set_encoder_config(
-    VP9_CONFIG *oxcf,
+    VP9EncoderConfig *oxcf,
     const vpx_codec_enc_cfg_t *cfg,
     const struct vp9_extracfg *extra_cfg) {
   oxcf->profile = cfg->g_profile;
@@ -300,26 +305,26 @@
 
   switch (cfg->g_pass) {
     case VPX_RC_ONE_PASS:
-      oxcf->mode = MODE_GOODQUALITY;
+      oxcf->mode = ONE_PASS_GOOD;
       break;
     case VPX_RC_FIRST_PASS:
-      oxcf->mode = MODE_FIRSTPASS;
+      oxcf->mode = TWO_PASS_FIRST;
       break;
     case VPX_RC_LAST_PASS:
-      oxcf->mode = MODE_SECONDPASS_BEST;
+      oxcf->mode = TWO_PASS_SECOND_BEST;
       break;
   }
 
   oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
                                                          : cfg->g_lag_in_frames;
 
-  oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
+  oxcf->rc_mode = RC_MODE_VBR;
   if (cfg->rc_end_usage == VPX_CQ)
-    oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
+    oxcf->rc_mode = RC_MODE_CONSTRAINED_QUALITY;
   else if (cfg->rc_end_usage == VPX_Q)
-    oxcf->end_usage = USAGE_CONSTANT_QUALITY;
+    oxcf->rc_mode = RC_MODE_CONSTANT_QUALITY;
   else if (cfg->rc_end_usage == VPX_CBR)
-    oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
+    oxcf->rc_mode = RC_MODE_CBR;
 
   oxcf->target_bandwidth         = cfg->rc_target_bitrate;
   oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
@@ -332,6 +337,10 @@
   oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
   oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;
 
+  oxcf->allow_spatial_resampling = cfg->rc_resize_allowed;
+  oxcf->scaled_frame_width       = cfg->rc_scaled_width;
+  oxcf->scaled_frame_height      = cfg->rc_scaled_height;
+
   oxcf->maximum_buffer_size     = cfg->rc_buf_sz;
   oxcf->starting_buffer_level   = cfg->rc_buf_initial_sz;
   oxcf->optimal_buffer_level    = cfg->rc_buf_optimal_sz;
@@ -347,7 +356,7 @@
 
   oxcf->key_freq               = cfg->kf_max_dist;
 
-  oxcf->cpu_used               =  extra_cfg->cpu_used;
+  oxcf->speed                  =  clamp(abs(extra_cfg->cpu_used), 0, 7);
   oxcf->encode_breakout        =  extra_cfg->static_thresh;
   oxcf->play_alternate         =  extra_cfg->enable_auto_alt_ref;
   oxcf->noise_sensitivity      =  extra_cfg->noise_sensitivity;
@@ -410,6 +419,9 @@
   printf("fixed_q: %d\n",  oxcf->fixed_q);
   printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q);
   printf("best_allowed_q: %d\n", oxcf->best_allowed_q);
+  printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling);
+  printf("scaled_frame_width: %d\n", oxcf->scaled_frame_width);
+  printf("scaled_frame_height: %d\n", oxcf->scaled_frame_height);
   printf("two_pass_vbrbias: %d\n",  oxcf->two_pass_vbrbias);
   printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section);
   printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section);
@@ -509,7 +521,8 @@
 #undef MAP
 }
 
-static vpx_codec_err_t encoder_common_init(vpx_codec_ctx_t *ctx) {
+static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
+                                    vpx_codec_priv_enc_mr_cfg_t *data) {
   vpx_codec_err_t res = VPX_CODEC_OK;
 
   if (ctx->priv == NULL) {
@@ -517,7 +530,8 @@
     vpx_codec_enc_cfg_t *cfg;
     struct vpx_codec_alg_priv *priv = calloc(1, sizeof(*priv));
 
-    if (priv == NULL) return VPX_CODEC_MEM_ERROR;
+    if (priv == NULL)
+      return VPX_CODEC_MEM_ERROR;
 
     ctx->priv = &priv->base;
     ctx->priv->sz = sizeof(*ctx->priv);
@@ -527,8 +541,7 @@
     ctx->priv->enc.total_encoders = 1;
 
     if (ctx->config.enc) {
-      // Update the reference to the config structure to an
-      // internal copy.
+      // Update the reference to the config structure to an internal copy.
       ctx->priv->alg_priv->cfg = *ctx->config.enc;
       ctx->config.enc = &ctx->priv->alg_priv->cfg;
     }
@@ -544,11 +557,11 @@
 
     priv->extra_cfg = extracfg_map[i].cfg;
     priv->extra_cfg.pkt_list = &priv->pkt_list.head;
-
-    // Maximum buffer size approximated based on having multiple ARF.
+     // Maximum buffer size approximated based on having multiple ARF.
     priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 8;
 
-    if (priv->cx_data_sz < 4096) priv->cx_data_sz = 4096;
+    if (priv->cx_data_sz < 4096)
+      priv->cx_data_sz = 4096;
 
     priv->cx_data = (unsigned char *)malloc(priv->cx_data_sz);
     if (priv->cx_data == NULL)
@@ -561,8 +574,8 @@
     if (res == VPX_CODEC_OK) {
       VP9_COMP *cpi;
       set_encoder_config(&ctx->priv->alg_priv->oxcf,
-                      &ctx->priv->alg_priv->cfg,
-                      &ctx->priv->alg_priv->extra_cfg);
+                         &ctx->priv->alg_priv->cfg,
+                         &ctx->priv->alg_priv->extra_cfg);
       cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
       if (cpi == NULL)
         res = VPX_CODEC_MEM_ERROR;
@@ -574,12 +587,6 @@
   return res;
 }
 
-
-static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
-                                    vpx_codec_priv_enc_mr_cfg_t *data) {
-  return encoder_common_init(ctx);
-}
-
 static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
   free(ctx->cx_data);
   vp9_remove_compressor(ctx->cpi);
@@ -591,7 +598,7 @@
                                     unsigned long duration,
                                     unsigned long deadline) {
   // Use best quality mode if no deadline is given.
-  MODE new_qc = MODE_BESTQUALITY;
+  MODE new_qc = ONE_PASS_BEST;
 
   if (deadline) {
     // Convert duration parameter from stream timebase to microseconds
@@ -601,14 +608,14 @@
 
     // If the deadline is more that the duration this frame is to be shown,
     // use good quality mode. Otherwise use realtime mode.
-    new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME;
+    new_qc = (deadline > duration_us) ? ONE_PASS_GOOD : REALTIME;
   }
 
   if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS)
-    new_qc = MODE_FIRSTPASS;
+    new_qc = TWO_PASS_FIRST;
   else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS)
-    new_qc = (new_qc == MODE_BESTQUALITY) ? MODE_SECONDPASS_BEST
-                                          : MODE_SECONDPASS;
+    new_qc = (new_qc == ONE_PASS_BEST) ? TWO_PASS_SECOND_BEST
+                                          : TWO_PASS_SECOND_GOOD;
 
   if (ctx->oxcf.mode != new_qc) {
     ctx->oxcf.mode = new_qc;
@@ -616,7 +623,8 @@
   }
 }
 
-
+// Turn on to test if supplemental superframe data breaks decoding
+// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
 static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
   uint8_t marker = 0xc0;
   unsigned int mask;
@@ -642,6 +650,20 @@
   if (ctx->pending_cx_data_sz + index_sz < ctx->cx_data_sz) {
     uint8_t *x = ctx->pending_cx_data + ctx->pending_cx_data_sz;
     int i, j;
+#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
+    uint8_t marker_test = 0xc0;
+    int mag_test = 2;     // 1 - 4
+    int frames_test = 4;  // 1 - 8
+    int index_sz_test = 2 + mag_test * frames_test;
+    marker_test |= frames_test - 1;
+    marker_test |= (mag_test - 1) << 3;
+    *x++ = marker_test;
+    for (i = 0; i < mag_test * frames_test; ++i)
+      *x++ = 0;  // fill up with arbitrary data
+    *x++ = marker_test;
+    ctx->pending_cx_data_sz += index_sz_test;
+    printf("Added supplemental superframe data\n");
+#endif
 
     *x++ = marker;
     for (i = 0; i < ctx->pending_frame_count; i++) {
@@ -654,6 +676,9 @@
     }
     *x++ = marker;
     ctx->pending_cx_data_sz += index_sz;
+#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
+    index_sz += index_sz_test;
+#endif
   }
   return index_sz;
 }
@@ -854,7 +879,6 @@
   return res;
 }
 
-
 static const vpx_codec_cx_pkt_t *encoder_get_cxdata(vpx_codec_alg_priv_t  *ctx,
                                                     vpx_codec_iter_t *iter) {
   return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
@@ -1128,6 +1152,8 @@
 
       0,                  // rc_dropframe_thresh
       0,                  // rc_resize_allowed
+      1,                  // rc_scaled_width
+      1,                  // rc_scaled_height
       60,                 // rc_resize_down_thresold
       30,                 // rc_resize_up_thresold
 
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 5ed7484..06b4823 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -43,6 +43,8 @@
   int                     dbg_color_b_modes_flag;
   int                     dbg_display_mv_flag;
 #endif
+  vpx_decrypt_cb          decrypt_cb;
+  void                   *decrypt_state;
   vpx_image_t             img;
   int                     img_setup;
   int                     img_avail;
@@ -94,9 +96,13 @@
   return VPX_CODEC_OK;
 }
 
-static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
-                                       unsigned int data_sz,
-                                       vpx_codec_stream_info_t *si) {
+static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
+                                                unsigned int data_sz,
+                                                vpx_codec_stream_info_t *si,
+                                                vpx_decrypt_cb decrypt_cb,
+                                                void *decrypt_state) {
+  uint8_t clear_buffer[9];
+
   if (data_sz <= 8)
     return VPX_CODEC_UNSUP_BITSTREAM;
 
@@ -106,6 +112,12 @@
   si->is_kf = 0;
   si->w = si->h = 0;
 
+  if (decrypt_cb) {
+    data_sz = MIN(sizeof(clear_buffer), data_sz);
+    decrypt_cb(decrypt_state, data, clear_buffer, data_sz);
+    data = clear_buffer;
+  }
+
   {
     struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
     const int frame_marker = vp9_rb_read_literal(&rb, 2);
@@ -159,6 +171,12 @@
   return VPX_CODEC_OK;
 }
 
+static vpx_codec_err_t decoder_peek_si(const uint8_t *data,
+                                       unsigned int data_sz,
+                                       vpx_codec_stream_info_t *si) {
+  return decoder_peek_si_internal(data, data_sz, si, NULL, NULL);
+}
+
 static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx,
                                       vpx_codec_stream_info_t *si) {
   const size_t sz = (si->sz >= sizeof(vp9_stream_info_t))
@@ -227,7 +245,7 @@
 }
 
 static void init_decoder(vpx_codec_alg_priv_t *ctx) {
-  VP9D_CONFIG oxcf;
+  VP9DecoderConfig oxcf;
   oxcf.width = ctx->si.w;
   oxcf.height = ctx->si.h;
   oxcf.version = 9;
@@ -264,7 +282,8 @@
   // of the heap.
   if (!ctx->si.h) {
     const vpx_codec_err_t res =
-        ctx->base.iface->dec.peek_si(*data, data_sz, &ctx->si);
+        decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb,
+                                 ctx->decrypt_state);
     if (res != VPX_CODEC_OK)
       return res;
   }
@@ -278,6 +297,11 @@
     ctx->decoder_init = 1;
   }
 
+  // Set these even if already initialized.  The caller may have changed the
+  // decrypt config between frames.
+  ctx->pbi->decrypt_cb = ctx->decrypt_cb;
+  ctx->pbi->decrypt_state = ctx->decrypt_state;
+
   cm = &ctx->pbi->common;
 
   if (vp9_receive_compressed_data(ctx->pbi, data_sz, data, deadline))
@@ -296,12 +320,25 @@
   return VPX_CODEC_OK;
 }
 
+static INLINE uint8_t read_marker(vpx_decrypt_cb decrypt_cb,
+                                  void *decrypt_state,
+                                  const uint8_t *data) {
+  if (decrypt_cb) {
+    uint8_t marker;
+    decrypt_cb(decrypt_state, data, &marker, 1);
+    return marker;
+  }
+  return *data;
+}
+
 static void parse_superframe_index(const uint8_t *data, size_t data_sz,
-                                   uint32_t sizes[8], int *count) {
+                                   uint32_t sizes[8], int *count,
+                                   vpx_decrypt_cb decrypt_cb,
+                                   void *decrypt_state) {
   uint8_t marker;
 
   assert(data_sz);
-  marker = data[data_sz - 1];
+  marker = read_marker(decrypt_cb, decrypt_state, data + data_sz - 1);
   *count = 0;
 
   if ((marker & 0xe0) == 0xc0) {
@@ -309,11 +346,22 @@
     const uint32_t mag = ((marker >> 3) & 0x3) + 1;
     const size_t index_sz = 2 + mag * frames;
 
-    if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
+    uint8_t marker2 = read_marker(decrypt_cb, decrypt_state,
+                                  data + data_sz - index_sz);
+
+    if (data_sz >= index_sz && marker2 == marker) {
       // found a valid superframe index
       uint32_t i, j;
       const uint8_t *x = &data[data_sz - index_sz + 1];
 
+      // frames has a maximum of 8 and mag has a maximum of 4.
+      uint8_t clear_buffer[32];
+      assert(sizeof(clear_buffer) >= frames * mag);
+      if (decrypt_cb) {
+        decrypt_cb(decrypt_state, x, clear_buffer, frames * mag);
+        x = clear_buffer;
+      }
+
       for (i = 0; i < frames; i++) {
         uint32_t this_sz = 0;
 
@@ -339,23 +387,31 @@
   if (data == NULL || data_sz == 0)
     return VPX_CODEC_INVALID_PARAM;
 
-  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
+  parse_superframe_index(data, data_sz, sizes, &frames_this_pts,
+                         ctx->decrypt_cb, ctx->decrypt_state);
 
   do {
-    // Skip over the superframe index, if present
-    if (data_sz && (*data_start & 0xe0) == 0xc0) {
-      const uint8_t marker = *data_start;
-      const uint32_t frames = (marker & 0x7) + 1;
-      const uint32_t mag = ((marker >> 3) & 0x3) + 1;
-      const uint32_t index_sz = 2 + mag * frames;
+    if (data_sz) {
+      uint8_t marker = read_marker(ctx->decrypt_cb, ctx->decrypt_state,
+                                   data_start);
+      // Skip over the superframe index, if present
+      if ((marker & 0xe0) == 0xc0) {
+        const uint32_t frames = (marker & 0x7) + 1;
+        const uint32_t mag = ((marker >> 3) & 0x3) + 1;
+        const uint32_t index_sz = 2 + mag * frames;
 
-      if (data_sz >= index_sz && data_start[index_sz - 1] == marker) {
-        data_start += index_sz;
-        data_sz -= index_sz;
-        if (data_start < data_end)
-          continue;
-        else
-          break;
+        if (data_sz >= index_sz) {
+          uint8_t marker2 = read_marker(ctx->decrypt_cb, ctx->decrypt_state,
+                                        data_start + index_sz - 1);
+          if (marker2 == marker) {
+            data_start += index_sz;
+            data_sz -= index_sz;
+            if (data_start < data_end)
+              continue;
+            else
+              break;
+          }
+        }
       }
     }
 
@@ -381,8 +437,13 @@
       break;
 
     // Account for suboptimal termination by the encoder.
-    while (data_start < data_end && *data_start == 0)
+    while (data_start < data_end) {
+      uint8_t marker3 = read_marker(ctx->decrypt_cb, ctx->decrypt_state,
+                                    data_start);
+      if (marker3)
+        break;
       data_start++;
+    }
 
     data_sz = (unsigned int)(data_end - data_start);
   } while (data_start < data_end);
@@ -565,6 +626,15 @@
   return VPX_CODEC_OK;
 }
 
+static vpx_codec_err_t ctrl_set_decryptor(vpx_codec_alg_priv_t *ctx,
+                                          int ctrl_id,
+                                          va_list args) {
+  vpx_decrypt_init *init = va_arg(args, vpx_decrypt_init *);
+  ctx->decrypt_cb = init ? init->decrypt_cb : NULL;
+  ctx->decrypt_state = init ? init->decrypt_state : NULL;
+  return VPX_CODEC_OK;
+}
+
 static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
   {VP8_COPY_REFERENCE,            ctrl_copy_reference},
 
@@ -576,6 +646,7 @@
   {VP8_SET_DBG_COLOR_B_MODES,     ctrl_set_dbg_options},
   {VP8_SET_DBG_DISPLAY_MV,        ctrl_set_dbg_options},
   {VP9_INVERT_TILE_DECODE_ORDER,  ctrl_set_invert_tile_order},
+  {VPXD_SET_DECRYPTOR,            ctrl_set_decryptor},
 
   // Getters
   {VP8D_GET_LAST_REF_UPDATES,     ctrl_get_last_ref_updates},
diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h
index 58256b2..d60883c 100644
--- a/vp9/vp9_iface_common.h
+++ b/vp9/vp9_iface_common.h
@@ -16,9 +16,11 @@
     * the Y, U, and V planes, nor other alignment adjustments that
     * might be representable by a YV12_BUFFER_CONFIG, so we just
     * initialize all the fields.*/
-  int bps = 12;
-  if (yv12->uv_height == yv12->y_height) {
-    if (yv12->uv_width == yv12->y_width) {
+  const int ss_x = yv12->uv_crop_width < yv12->y_crop_width;
+  const int ss_y = yv12->uv_crop_height < yv12->y_crop_height;
+  int bps;
+  if (!ss_y) {
+    if (!ss_x) {
       img->fmt = VPX_IMG_FMT_I444;
       bps = 24;
     } else {
@@ -27,13 +29,14 @@
     }
   } else {
     img->fmt = VPX_IMG_FMT_I420;
+    bps = 12;
   }
   img->w = yv12->y_stride;
   img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3);
   img->d_w = yv12->y_crop_width;
   img->d_h = yv12->y_crop_height;
-  img->x_chroma_shift = yv12->uv_width < yv12->y_width;
-  img->y_chroma_shift = yv12->uv_height < yv12->y_height;
+  img->x_chroma_shift = ss_x;
+  img->y_chroma_shift = ss_y;
   img->planes[VPX_PLANE_Y] = yv12->y_buffer;
   img->planes[VPX_PLANE_U] = yv12->u_buffer;
   img->planes[VPX_PLANE_V] = yv12->v_buffer;
diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk
index da6c0f8..5e88793 100644
--- a/vp9/vp9cx.mk
+++ b/vp9/vp9cx.mk
@@ -18,6 +18,8 @@
 VP9_CX_SRCS-yes += vp9_cx_iface.c
 
 VP9_CX_SRCS-yes += encoder/vp9_bitstream.c
+VP9_CX_SRCS-yes += encoder/vp9_context_tree.c
+VP9_CX_SRCS-yes += encoder/vp9_context_tree.h
 VP9_CX_SRCS-yes += encoder/vp9_cost.h
 VP9_CX_SRCS-yes += encoder/vp9_cost.c
 VP9_CX_SRCS-yes += encoder/vp9_dct.c
@@ -40,7 +42,7 @@
 VP9_CX_SRCS-yes += encoder/vp9_lookahead.c
 VP9_CX_SRCS-yes += encoder/vp9_lookahead.h
 VP9_CX_SRCS-yes += encoder/vp9_mcomp.h
-VP9_CX_SRCS-yes += encoder/vp9_onyx_int.h
+VP9_CX_SRCS-yes += encoder/vp9_encoder.h
 VP9_CX_SRCS-yes += encoder/vp9_quantize.h
 VP9_CX_SRCS-yes += encoder/vp9_ratectrl.h
 VP9_CX_SRCS-yes += encoder/vp9_rdopt.h
@@ -50,7 +52,7 @@
 VP9_CX_SRCS-yes += encoder/vp9_treewriter.h
 VP9_CX_SRCS-yes += encoder/vp9_variance.h
 VP9_CX_SRCS-yes += encoder/vp9_mcomp.c
-VP9_CX_SRCS-yes += encoder/vp9_onyx_if.c
+VP9_CX_SRCS-yes += encoder/vp9_encoder.c
 VP9_CX_SRCS-yes += encoder/vp9_picklpf.c
 VP9_CX_SRCS-yes += encoder/vp9_picklpf.h
 VP9_CX_SRCS-yes += encoder/vp9_quantize.c
@@ -87,8 +89,6 @@
 VP9_CX_SRCS-yes += encoder/vp9_mbgraph.c
 VP9_CX_SRCS-yes += encoder/vp9_mbgraph.h
 
-
-VP9_CX_SRCS-$(ARCH_X86)$(ARCH_X86_64) += encoder/x86/vp9_mcomp_x86.h
 VP9_CX_SRCS-$(HAVE_MMX) += encoder/x86/vp9_variance_mmx.c
 VP9_CX_SRCS-$(HAVE_MMX) += encoder/x86/vp9_variance_impl_mmx.asm
 VP9_CX_SRCS-$(HAVE_MMX) += encoder/x86/vp9_sad_mmx.asm
@@ -96,7 +96,6 @@
 VP9_CX_SRCS-$(HAVE_AVX2) += encoder/x86/vp9_variance_impl_intrin_avx2.c
 VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_sad4d_sse2.asm
 VP9_CX_SRCS-$(HAVE_AVX2) += encoder/x86/vp9_sad4d_intrin_avx2.c
-VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_subpel_variance_impl_sse2.asm
 VP9_CX_SRCS-$(HAVE_AVX2) += encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c
 VP9_CX_SRCS-$(HAVE_SSE2) += encoder/x86/vp9_temporal_filter_apply_sse2.asm
 VP9_CX_SRCS-$(HAVE_SSE3) += encoder/x86/vp9_sad_sse3.asm
@@ -112,6 +111,7 @@
 
 ifeq ($(ARCH_X86_64),yes)
 VP9_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/vp9_quantize_ssse3.asm
+VP9_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/vp9_dct_ssse3.asm
 endif
 VP9_CX_SRCS-$(HAVE_SSSE3) += encoder/x86/vp9_sad_ssse3.asm
 VP9_CX_SRCS-$(HAVE_SSE4_1) += encoder/x86/vp9_sad_sse4.asm
diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h
index 8944a26..bc8df80 100644
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -160,8 +160,10 @@
                                           scale as used by the rc_*_quantizer config
                                           parameters */
   VP8E_SET_ARNR_MAXFRAMES,         /**< control function to set the max number of frames blurred creating arf*/
-  VP8E_SET_ARNR_STRENGTH,         /**< control function to set the filter strength for the arf */
-  VP8E_SET_ARNR_TYPE,         /**< control function to set the type of filter to use for the arf*/
+  VP8E_SET_ARNR_STRENGTH,          //!< control function to set the filter
+                                   //!< strength for the arf
+  VP8E_SET_ARNR_TYPE,              //!< control function to set the type of
+                                   //!< filter to use for the arf
   VP8E_SET_TUNING,                 /**< control function to set visual tuning */
   /*!\brief control function to set constrained quality level
    *
diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h
index bde77c2..bd7f19c 100644
--- a/vpx/vp8dx.h
+++ b/vpx/vp8dx.h
@@ -66,10 +66,11 @@
   VP8D_GET_LAST_REF_USED,
 
   /** decryption function to decrypt encoded buffer data immediately
-   * before decoding. Takes a vp8_decrypt_init, which contains
+   * before decoding. Takes a vpx_decrypt_init, which contains
    * a callback function and opaque context pointer.
    */
-  VP8D_SET_DECRYPTOR,
+  VPXD_SET_DECRYPTOR,
+  VP8D_SET_DECRYPTOR = VPXD_SET_DECRYPTOR,
 
   /** control function to get the display dimensions for the current frame. */
   VP9D_GET_DISPLAY_SIZE,
@@ -80,19 +81,28 @@
   VP8_DECODER_CTRL_ID_MAX
 };
 
+/** Decrypt n bytes of data from input -> output, using the decrypt_state
+ *  passed in VPXD_SET_DECRYPTOR.
+ */
+typedef void (*vpx_decrypt_cb)(void *decrypt_state, const unsigned char *input,
+                               unsigned char *output, int count);
+
 /*!\brief Structure to hold decryption state
  *
  * Defines a structure to hold the decryption state and access function.
  */
-typedef struct vp8_decrypt_init {
-    /** Decrypt n bytes of data from input -> output, using the decrypt_state
-     *  passed in VP8D_SET_DECRYPTOR.
-     */
-    void (*decrypt_cb)(void *decrypt_state, const unsigned char *input,
-                       unsigned char *output, int count);
+typedef struct vpx_decrypt_init {
+    /*! Decrypt callback. */
+    vpx_decrypt_cb decrypt_cb;
+
     /*! Decryption state. */
     void *decrypt_state;
-} vp8_decrypt_init;
+} vpx_decrypt_init;
+
+/*!\brief A deprecated alias for vpx_decrypt_init.
+ */
+typedef vpx_decrypt_init vp8_decrypt_init;
+
 
 /*!\brief VP8 decoder control function parameter type
  *
@@ -102,11 +112,12 @@
  */
 
 
-VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES,   int *)
-VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED,    int *)
-VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED,      int *)
-VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR,          vp8_decrypt_init *)
-VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE,       int *)
+VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES,    int *)
+VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED,     int *)
+VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED,       int *)
+VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR,           vpx_decrypt_init *)
+VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR,           vpx_decrypt_init *)
+VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE,        int *)
 VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int)
 
 /*! @} - end defgroup vp8_decoder */
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index 2c882c1..571ad3f 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -396,6 +396,19 @@
      */
     unsigned int           rc_resize_allowed;
 
+    /*!\brief Internal coded frame width.
+     *
+     * If spatial resampling is enabled this specifies the width of the
+     * encoded frame.
+     */
+    unsigned int           rc_scaled_width;
+
+    /*!\brief Internal coded frame height.
+     *
+     * If spatial resampling is enabled this specifies the height of the
+     * encoded frame.
+     */
+    unsigned int           rc_scaled_height;
 
     /*!\brief Spatial resampling up watermark.
      *
diff --git a/vpx/vpx_image.h b/vpx/vpx_image.h
index 8d0f4ec..d45b003 100644
--- a/vpx/vpx_image.h
+++ b/vpx/vpx_image.h
@@ -34,7 +34,7 @@
 #define VPX_IMG_FMT_PLANAR     0x100  /**< Image is a planar format */
 #define VPX_IMG_FMT_UV_FLIP    0x200  /**< V plane precedes U plane in memory */
 #define VPX_IMG_FMT_HAS_ALPHA  0x400  /**< Image has an alpha channel component */
-
+#define VPX_IMG_FMT_HIGH       0x800  /**< Image uses 16bit framebuffer */
 
   /*!\brief List of supported image formats */
   typedef enum vpx_img_fmt {
@@ -58,7 +58,10 @@
     VPX_IMG_FMT_VPXI420 = VPX_IMG_FMT_PLANAR | 4,
     VPX_IMG_FMT_I422    = VPX_IMG_FMT_PLANAR | 5,
     VPX_IMG_FMT_I444    = VPX_IMG_FMT_PLANAR | 6,
-    VPX_IMG_FMT_444A    = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 7
+    VPX_IMG_FMT_444A    = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 7,
+    VPX_IMG_FMT_I42016    = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGH,
+    VPX_IMG_FMT_I42216    = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGH,
+    VPX_IMG_FMT_I44416    = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGH
   } vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */
 
 #if !defined(VPX_CODEC_DISABLE_COMPAT) || !VPX_CODEC_DISABLE_COMPAT
diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c
index 5e95d31..3eaf50e 100644
--- a/vpx_scale/generic/yv12config.c
+++ b/vpx_scale/generic/yv12config.c
@@ -183,8 +183,7 @@
       ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32);
     } else if (frame_size > ybf->buffer_alloc_sz) {
       // Allocation to hold larger frame, or first allocation.
-      if (ybf->buffer_alloc)
-        vpx_free(ybf->buffer_alloc);
+      vpx_free(ybf->buffer_alloc);
       ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, frame_size);
       if (!ybf->buffer_alloc)
         return -1;
diff --git a/vpxdec.c b/vpxdec.c
index 4c37234..6356961 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -119,7 +119,7 @@
 #endif
 
 static int vpx_image_scale(vpx_image_t *src, vpx_image_t *dst,
-                           FilterMode mode) {
+                           FilterModeEnum mode) {
   assert(src->fmt == VPX_IMG_FMT_I420);
   assert(dst->fmt == VPX_IMG_FMT_I420);
   return I420Scale(src->planes[VPX_PLANE_Y], src->stride[VPX_PLANE_Y],
diff --git a/vpxenc.c b/vpxenc.c
index 00d3e3e..8e8ed23 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -123,55 +123,6 @@
   return 0;
 }
 
-#if CONFIG_WEBM_IO
-/* Murmur hash derived from public domain reference implementation at
- *   http:// sites.google.com/site/murmurhash/
- */
-static unsigned int murmur(const void *key, int len, unsigned int seed) {
-  const unsigned int m = 0x5bd1e995;
-  const int r = 24;
-
-  unsigned int h = seed ^ len;
-
-  const unsigned char *data = (const unsigned char *)key;
-
-  while (len >= 4) {
-    unsigned int k;
-
-    k  = (unsigned int)data[0];
-    k |= (unsigned int)data[1] << 8;
-    k |= (unsigned int)data[2] << 16;
-    k |= (unsigned int)data[3] << 24;
-
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-
-    h *= m;
-    h ^= k;
-
-    data += 4;
-    len -= 4;
-  }
-
-  switch (len) {
-    case 3:
-      h ^= data[2] << 16;
-    case 2:
-      h ^= data[1] << 8;
-    case 1:
-      h ^= data[0];
-      h *= m;
-  };
-
-  h ^= h >> 13;
-  h *= m;
-  h ^= h >> 15;
-
-  return h;
-}
-#endif  // CONFIG_WEBM_IO
-
 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
                                            "Debug mode (makes output deterministic)");
 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
@@ -284,6 +235,10 @@
                                                     "Temporal resampling threshold (buf %)");
 static const arg_def_t resize_allowed     = ARG_DEF(NULL, "resize-allowed", 1,
                                                     "Spatial resampling enabled (bool)");
+static const arg_def_t resize_width       = ARG_DEF(NULL, "resize-width", 1,
+                                                    "Width of encoded frame");
+static const arg_def_t resize_height      = ARG_DEF(NULL, "resize-height", 1,
+                                                    "Height of encoded frame");
 static const arg_def_t resize_up_thresh   = ARG_DEF(NULL, "resize-up", 1,
                                                     "Upscale threshold (buf %)");
 static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1,
@@ -314,10 +269,10 @@
 static const arg_def_t buf_optimal_sz     = ARG_DEF(NULL, "buf-optimal-sz", 1,
                                                     "Client optimal buffer size (ms)");
 static const arg_def_t *rc_args[] = {
-  &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh,
-  &end_usage, &target_bitrate, &min_quantizer, &max_quantizer,
-  &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz,
-  NULL
+  &dropframe_thresh, &resize_allowed, &resize_width, &resize_height,
+  &resize_up_thresh, &resize_down_thresh, &end_usage, &target_bitrate,
+  &min_quantizer, &max_quantizer, &undershoot_pct, &overshoot_pct, &buf_sz,
+  &buf_initial_sz, &buf_optimal_sz, NULL
 };
 
 
@@ -400,11 +355,11 @@
     NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
 static const arg_def_t aq_mode = ARG_DEF(
     NULL, "aq-mode", 1,
-    "Adaptive q mode (0: off (by default), 1: variance 2: complexity, "
+    "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
     "3: cyclic refresh)");
 static const arg_def_t frame_periodic_boost = ARG_DEF(
     NULL, "frame_boost", 1,
-    "Enable frame periodic boost (0: off (by default), 1: on)");
+    "Enable frame periodic boost (0: off (default), 1: on)");
 
 static const arg_def_t *vp9_args[] = {
   &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh,
@@ -619,7 +574,6 @@
   FILE                     *file;
   struct rate_hist         *rate_hist;
   struct EbmlGlobal         ebml;
-  uint32_t                  hash;
   uint64_t                  psnr_sse_total;
   uint64_t                  psnr_samples_total;
   double                    psnr_totals[4];
@@ -841,7 +795,9 @@
     stream->config.stereo_fmt = STEREO_FORMAT_MONO;
     stream->config.write_webm = 1;
 #if CONFIG_WEBM_IO
-    stream->ebml.last_pts_ms = -1;
+    stream->ebml.last_pts_ns = -1;
+    stream->ebml.writer = NULL;
+    stream->ebml.segment = NULL;
 #endif
 
     /* Allows removal of the application version from the EBML tags */
@@ -931,6 +887,10 @@
       config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
     } else if (arg_match(&arg, &resize_allowed, argi)) {
       config->cfg.rc_resize_allowed = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &resize_width, argi)) {
+      config->cfg.rc_scaled_width = arg_parse_uint(&arg);
+    } else if (arg_match(&arg, &resize_height, argi)) {
+      config->cfg.rc_scaled_height = arg_parse_uint(&arg);
     } else if (arg_match(&arg, &resize_up_thresh, argi)) {
       config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
     } else if (arg_match(&arg, &resize_down_thresh, argi)) {
@@ -1115,6 +1075,8 @@
   SHOW(g_lag_in_frames);
   SHOW(rc_dropframe_thresh);
   SHOW(rc_resize_allowed);
+  SHOW(rc_scaled_width);
+  SHOW(rc_scaled_height);
   SHOW(rc_resize_up_thresh);
   SHOW(rc_resize_down_thresh);
   SHOW(rc_end_usage);
@@ -1176,9 +1138,7 @@
 
 #if CONFIG_WEBM_IO
   if (stream->config.write_webm) {
-    write_webm_file_footer(&stream->ebml, stream->hash);
-    free(stream->ebml.cue_list);
-    stream->ebml.cue_list = NULL;
+    write_webm_file_footer(&stream->ebml);
   }
 #endif
 
@@ -1321,7 +1281,7 @@
   *got_data = 0;
   while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) {
     static size_t fsize = 0;
-    static off_t ivf_header_pos = 0;
+    static int64_t ivf_header_pos = 0;
 
     switch (pkt->kind) {
       case VPX_CODEC_CX_FRAME_PKT:
@@ -1334,12 +1294,6 @@
         update_rate_histogram(stream->rate_hist, cfg, pkt);
 #if CONFIG_WEBM_IO
         if (stream->config.write_webm) {
-          /* Update the hash */
-          if (!stream->ebml.debug)
-            stream->hash = murmur(pkt->data.frame.buf,
-                                  (int)pkt->data.frame.sz,
-                                  stream->hash);
-
           write_webm_block(&stream->ebml, cfg, pkt);
         }
 #endif
@@ -1353,7 +1307,7 @@
             fsize += pkt->data.frame.sz;
 
             if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
-              off_t currpos = ftello(stream->file);
+              const int64_t currpos = ftello(stream->file);
               fseeko(stream->file, ivf_header_pos, SEEK_SET);
               ivf_write_frame_size(stream->file, fsize);
               fseeko(stream->file, currpos, SEEK_SET);
@@ -1580,7 +1534,7 @@
     int frames_in = 0, seen_frames = 0;
     int64_t estimated_time_left = -1;
     int64_t average_rate = -1;
-    off_t lagged_count = 0;
+    int64_t lagged_count = 0;
 
     open_input_file(&input);
 
@@ -1713,15 +1667,15 @@
           int64_t rate;
 
           if (global.limit) {
-            off_t frame_in_lagged = (seen_frames - lagged_count) * 1000;
+            const int64_t frame_in_lagged = (seen_frames - lagged_count) * 1000;
 
             rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0;
             remaining = 1000 * (global.limit - global.skip_frames
                                 - seen_frames + lagged_count);
           } else {
-            off_t input_pos = ftello(input.file);
-            off_t input_pos_lagged = input_pos - lagged_count;
-            int64_t limit = input.length;
+            const int64_t input_pos = ftello(input.file);
+            const int64_t input_pos_lagged = input_pos - lagged_count;
+            const int64_t limit = input.length;
 
             rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0;
             remaining = limit - input_pos + lagged_count;
diff --git a/webmdec.c b/webmdec.c
deleted file mode 100644
index 7cacdf9..0000000
--- a/webmdec.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "./webmdec.h"
-
-#include <stdarg.h>
-
-#include "third_party/nestegg/include/nestegg/nestegg.h"
-
-static int nestegg_read_cb(void *buffer, size_t length, void *userdata) {
-  FILE *f = userdata;
-
-  if (fread(buffer, 1, length, f) < length) {
-    if (ferror(f))
-      return -1;
-    if (feof(f))
-      return 0;
-  }
-  return 1;
-}
-
-static int nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
-  switch (whence) {
-    case NESTEGG_SEEK_SET:
-      whence = SEEK_SET;
-      break;
-    case NESTEGG_SEEK_CUR:
-      whence = SEEK_CUR;
-      break;
-    case NESTEGG_SEEK_END:
-      whence = SEEK_END;
-      break;
-  };
-  return fseek(userdata, (int32_t)offset, whence) ? -1 : 0;
-}
-
-static int64_t nestegg_tell_cb(void *userdata) {
-  return ftell(userdata);
-}
-
-static void nestegg_log_cb(nestegg *context,
-                           unsigned int severity,
-                           char const *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  vfprintf(stderr, format, ap);
-  fprintf(stderr, "\n");
-  va_end(ap);
-}
-
-int file_is_webm(struct WebmInputContext *webm_ctx,
-                 struct VpxInputContext *vpx_ctx) {
-  uint32_t i, n;
-  int track_type = -1;
-  int codec_id;
-
-  nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
-  nestegg_video_params params;
-
-  io.userdata = vpx_ctx->file;
-  if (nestegg_init(&webm_ctx->nestegg_ctx, io, NULL, -1))
-    goto fail;
-
-  if (nestegg_track_count(webm_ctx->nestegg_ctx, &n))
-    goto fail;
-
-  for (i = 0; i < n; i++) {
-    track_type = nestegg_track_type(webm_ctx->nestegg_ctx, i);
-
-    if (track_type == NESTEGG_TRACK_VIDEO)
-      break;
-    else if (track_type < 0)
-      goto fail;
-  }
-
-  codec_id = nestegg_track_codec_id(webm_ctx->nestegg_ctx, i);
-  if (codec_id == NESTEGG_CODEC_VP8) {
-    vpx_ctx->fourcc = VP8_FOURCC;
-  } else if (codec_id == NESTEGG_CODEC_VP9) {
-    vpx_ctx->fourcc = VP9_FOURCC;
-  } else {
-    fatal("Not VPx video, quitting.\n");
-  }
-
-  webm_ctx->video_track = i;
-
-  if (nestegg_track_video_params(webm_ctx->nestegg_ctx, i, &params))
-    goto fail;
-
-  vpx_ctx->framerate.denominator = 0;
-  vpx_ctx->framerate.numerator = 0;
-  vpx_ctx->width = params.width;
-  vpx_ctx->height = params.height;
-
-  return 1;
-
- fail:
-  webm_ctx->nestegg_ctx = NULL;
-  rewind(vpx_ctx->file);
-
-  return 0;
-}
-
-int webm_read_frame(struct WebmInputContext *webm_ctx,
-                    uint8_t **buffer,
-                    size_t *bytes_in_buffer,
-                    size_t *buffer_size) {
-  if (webm_ctx->chunk >= webm_ctx->chunks) {
-    uint32_t track;
-
-    do {
-      /* End of this packet, get another. */
-      if (webm_ctx->pkt) {
-        nestegg_free_packet(webm_ctx->pkt);
-        webm_ctx->pkt = NULL;
-      }
-
-      if (nestegg_read_packet(webm_ctx->nestegg_ctx, &webm_ctx->pkt) <= 0 ||
-          nestegg_packet_track(webm_ctx->pkt, &track)) {
-        return 1;
-      }
-    } while (track != webm_ctx->video_track);
-
-    if (nestegg_packet_count(webm_ctx->pkt, &webm_ctx->chunks))
-      return 1;
-
-    webm_ctx->chunk = 0;
-  }
-
-  if (nestegg_packet_data(webm_ctx->pkt, webm_ctx->chunk,
-                          buffer, bytes_in_buffer)) {
-    return 1;
-  }
-
-  webm_ctx->chunk++;
-  return 0;
-}
-
-int webm_guess_framerate(struct WebmInputContext *webm_ctx,
-                         struct VpxInputContext *vpx_ctx) {
-  uint32_t i;
-  uint64_t tstamp = 0;
-
-  /* Check to see if we can seek before we parse any data. */
-  if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) {
-    warn("Failed to guess framerate (no Cues), set to 30fps.\n");
-    vpx_ctx->framerate.numerator = 30;
-    vpx_ctx->framerate.denominator  = 1;
-    return 0;
-  }
-
-  /* Guess the framerate. Read up to 1 second, or 50 video packets,
-   * whichever comes first.
-   */
-  for (i = 0; tstamp < 1000000000 && i < 50;) {
-    nestegg_packet *pkt;
-    uint32_t track;
-
-    if (nestegg_read_packet(webm_ctx->nestegg_ctx, &pkt) <= 0)
-      break;
-
-    nestegg_packet_track(pkt, &track);
-    if (track == webm_ctx->video_track) {
-      nestegg_packet_tstamp(pkt, &tstamp);
-      ++i;
-    }
-
-    nestegg_free_packet(pkt);
-  }
-
-  if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0))
-    goto fail;
-
-  vpx_ctx->framerate.numerator = (i - 1) * 1000000;
-  vpx_ctx->framerate.denominator = (int)(tstamp / 1000);
-  return 0;
-
- fail:
-  nestegg_destroy(webm_ctx->nestegg_ctx);
-  webm_ctx->nestegg_ctx = NULL;
-  rewind(vpx_ctx->file);
-  return 1;
-}
-
-void webm_free(struct WebmInputContext *webm_ctx) {
-  if (webm_ctx && webm_ctx->nestegg_ctx) {
-    if (webm_ctx->pkt)
-      nestegg_free_packet(webm_ctx->pkt);
-    nestegg_destroy(webm_ctx->nestegg_ctx);
-  }
-}
diff --git a/webmdec.cc b/webmdec.cc
new file mode 100644
index 0000000..eb89bef
--- /dev/null
+++ b/webmdec.cc
@@ -0,0 +1,219 @@
+/*
+ *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "./webmdec.h"
+
+#include <cstring>
+#include <cstdio>
+
+#include "third_party/libwebm/mkvparser.hpp"
+#include "third_party/libwebm/mkvreader.hpp"
+
+namespace {
+
+void reset(struct WebmInputContext *const webm_ctx) {
+  if (webm_ctx->reader != NULL) {
+    mkvparser::MkvReader *const reader =
+        reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
+    delete reader;
+  }
+  if (webm_ctx->segment != NULL) {
+    mkvparser::Segment *const segment =
+        reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
+    delete segment;
+  }
+  if (webm_ctx->buffer != NULL) {
+    delete[] webm_ctx->buffer;
+  }
+  webm_ctx->reader = NULL;
+  webm_ctx->segment = NULL;
+  webm_ctx->buffer = NULL;
+  webm_ctx->cluster = NULL;
+  webm_ctx->block_entry = NULL;
+  webm_ctx->block = NULL;
+  webm_ctx->block_frame_index = 0;
+  webm_ctx->video_track_index = 0;
+  webm_ctx->timestamp_ns = 0;
+}
+
+void get_first_cluster(struct WebmInputContext *const webm_ctx) {
+  mkvparser::Segment *const segment =
+      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
+  const mkvparser::Cluster *const cluster = segment->GetFirst();
+  webm_ctx->cluster = cluster;
+}
+
+void rewind_and_reset(struct WebmInputContext *const webm_ctx,
+                      struct VpxInputContext *const vpx_ctx) {
+  rewind(vpx_ctx->file);
+  reset(webm_ctx);
+}
+
+}  // namespace
+
+int file_is_webm(struct WebmInputContext *webm_ctx,
+                 struct VpxInputContext *vpx_ctx) {
+  mkvparser::MkvReader *const reader = new mkvparser::MkvReader(vpx_ctx->file);
+  webm_ctx->reader = reader;
+
+  mkvparser::EBMLHeader header;
+  long long pos = 0;
+  if (header.Parse(reader, pos) < 0) {
+    rewind_and_reset(webm_ctx, vpx_ctx);
+    return 0;
+  }
+
+  mkvparser::Segment* segment;
+  if (mkvparser::Segment::CreateInstance(reader, pos, segment)) {
+    rewind_and_reset(webm_ctx, vpx_ctx);
+    return 0;
+  }
+  webm_ctx->segment = segment;
+  if (segment->Load() < 0) {
+    rewind_and_reset(webm_ctx, vpx_ctx);
+    return 0;
+  }
+
+  const mkvparser::Tracks *const tracks = segment->GetTracks();
+  const mkvparser::VideoTrack* video_track = NULL;
+  for (unsigned long i = 0; i < tracks->GetTracksCount(); ++i) {
+    const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
+    if (track->GetType() == mkvparser::Track::kVideo) {
+      video_track = static_cast<const mkvparser::VideoTrack*>(track);
+      webm_ctx->video_track_index = track->GetNumber();
+      break;
+    }
+  }
+
+  if (video_track == NULL) {
+    rewind_and_reset(webm_ctx, vpx_ctx);
+    return 0;
+  }
+
+  if (!strncmp(video_track->GetCodecId(), "V_VP8", 5)) {
+    vpx_ctx->fourcc = VP8_FOURCC;
+  } else if (!strncmp(video_track->GetCodecId(), "V_VP9", 5)) {
+    vpx_ctx->fourcc = VP9_FOURCC;
+  } else {
+    rewind_and_reset(webm_ctx, vpx_ctx);
+    return 0;
+  }
+
+  vpx_ctx->framerate.denominator = 0;
+  vpx_ctx->framerate.numerator = 0;
+  vpx_ctx->width = video_track->GetWidth();
+  vpx_ctx->height = video_track->GetHeight();
+
+  get_first_cluster(webm_ctx);
+
+  return 1;
+}
+
+int webm_read_frame(struct WebmInputContext *webm_ctx,
+                    uint8_t **buffer,
+                    size_t *bytes_in_buffer,
+                    size_t *buffer_size) {
+  mkvparser::Segment *const segment =
+      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
+  const mkvparser::Cluster* cluster =
+      reinterpret_cast<const mkvparser::Cluster*>(webm_ctx->cluster);
+  const mkvparser::Block *block =
+      reinterpret_cast<const mkvparser::Block*>(webm_ctx->block);
+  const mkvparser::BlockEntry *block_entry =
+      reinterpret_cast<const mkvparser::BlockEntry*>(webm_ctx->block_entry);
+  bool block_entry_eos = false;
+  do {
+    long status = 0;
+    bool get_new_block = false;
+    if (block_entry == NULL && !block_entry_eos) {
+      status = cluster->GetFirst(block_entry);
+      get_new_block = true;
+    } else if (block_entry_eos || block_entry->EOS()) {
+      cluster = segment->GetNext(cluster);
+      if (cluster == NULL || cluster->EOS()) {
+        *bytes_in_buffer = 0;
+        return 1;
+      }
+      status = cluster->GetFirst(block_entry);
+      block_entry_eos = false;
+      get_new_block = true;
+    } else if (block == NULL ||
+               webm_ctx->block_frame_index == block->GetFrameCount() ||
+               block->GetTrackNumber() != webm_ctx->video_track_index) {
+      status = cluster->GetNext(block_entry, block_entry);
+      if (block_entry == NULL || block_entry->EOS()) {
+        block_entry_eos = true;
+        continue;
+      }
+      get_new_block = true;
+    }
+    if (status) {
+      return -1;
+    }
+    if (get_new_block) {
+      block = block_entry->GetBlock();
+      webm_ctx->block_frame_index = 0;
+    }
+  } while (block->GetTrackNumber() != webm_ctx->video_track_index ||
+           block_entry_eos);
+
+  webm_ctx->cluster = cluster;
+  webm_ctx->block_entry = block_entry;
+  webm_ctx->block = block;
+
+  const mkvparser::Block::Frame& frame =
+      block->GetFrame(webm_ctx->block_frame_index);
+  ++webm_ctx->block_frame_index;
+  if (frame.len > static_cast<long>(*buffer_size)) {
+    delete[] *buffer;
+    *buffer = new uint8_t[frame.len];
+    if (*buffer == NULL) {
+      return -1;
+    }
+    *buffer_size = frame.len;
+    webm_ctx->buffer = *buffer;
+  }
+  *bytes_in_buffer = frame.len;
+  webm_ctx->timestamp_ns = block->GetTime(cluster);
+
+  mkvparser::MkvReader *const reader =
+      reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
+  return frame.Read(reader, *buffer) ? -1 : 0;
+}
+
+int webm_guess_framerate(struct WebmInputContext *webm_ctx,
+                         struct VpxInputContext *vpx_ctx) {
+  uint32_t i = 0;
+  uint8_t *buffer = NULL;
+  size_t bytes_in_buffer = 0;
+  size_t buffer_size = 0;
+  while (webm_ctx->timestamp_ns < 1000000000 && i < 50) {
+    if (webm_read_frame(webm_ctx, &buffer, &bytes_in_buffer, &buffer_size)) {
+      break;
+    }
+    ++i;
+  }
+  vpx_ctx->framerate.numerator = (i - 1) * 1000000;
+  vpx_ctx->framerate.denominator =
+      static_cast<int>(webm_ctx->timestamp_ns / 1000);
+  delete[] buffer;
+
+  get_first_cluster(webm_ctx);
+  webm_ctx->block = NULL;
+  webm_ctx->block_entry = NULL;
+  webm_ctx->block_frame_index = 0;
+  webm_ctx->timestamp_ns = 0;
+
+  return 0;
+}
+
+void webm_free(struct WebmInputContext *webm_ctx) {
+  reset(webm_ctx);
+}
diff --git a/webmdec.h b/webmdec.h
index fa5a52e..29b815d 100644
--- a/webmdec.h
+++ b/webmdec.h
@@ -16,29 +16,53 @@
 extern "C" {
 #endif
 
-struct nestegg;
-struct nestegg_packet;
 struct VpxInputContext;
 
 struct WebmInputContext {
-  uint32_t chunk;
-  uint32_t chunks;
-  uint32_t video_track;
-  struct nestegg *nestegg_ctx;
-  struct nestegg_packet *pkt;
+  void *reader;
+  void *segment;
+  uint8_t *buffer;
+  const void *cluster;
+  const void *block_entry;
+  const void *block;
+  int block_frame_index;
+  int video_track_index;
+  uint64_t timestamp_ns;
 };
 
+// Checks if the input is a WebM file. If so, initializes WebMInputContext so
+// that webm_read_frame can be called to retrieve a video frame.
+// Returns 1 on success and 0 on failure or input is not WebM file.
+// TODO(vigneshv): Refactor this function into two smaller functions specific
+// to their task.
 int file_is_webm(struct WebmInputContext *webm_ctx,
                  struct VpxInputContext *vpx_ctx);
 
+// Reads a WebM Video Frame. Memory for the buffer is created, owned and managed
+// by this function. For the first call, |buffer| should be NULL and
+// |*bytes_in_buffer| should be 0. Once all the frames are read and used,
+// webm_free() should be called, otherwise there will be a leak.
+// Parameters:
+//      webm_ctx - WebmInputContext object
+//      buffer - pointer where the frame data will be filled.
+//      bytes_in_buffer - pointer to buffer size.
+//      buffer_size - unused TODO(vigneshv): remove this
+// Return values:
+//      0 - Success
+//      1 - End of Stream
+//     -1 - Error
+// TODO(vigneshv): Make the return values consistent across all functions in
+// this file.
 int webm_read_frame(struct WebmInputContext *webm_ctx,
                     uint8_t **buffer,
                     size_t *bytes_in_buffer,
                     size_t *buffer_size);
 
+// Guesses the frame rate of the input file based on the container timestamps.
 int webm_guess_framerate(struct WebmInputContext *webm_ctx,
                          struct VpxInputContext *vpx_ctx);
 
+// Resets the WebMInputContext.
 void webm_free(struct WebmInputContext *webm_ctx);
 
 #ifdef __cplusplus
diff --git a/webmenc.c b/webmenc.c
deleted file mode 100644
index 17bbeec..0000000
--- a/webmenc.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-#include "webmenc.h"
-
-#include <limits.h>
-#include <string.h>
-
-#include "third_party/libmkv/EbmlWriter.h"
-#include "third_party/libmkv/EbmlIDs.h"
-
-void Ebml_Write(struct EbmlGlobal *glob,
-                const void *buffer_in,
-                unsigned long len) {
-  (void) fwrite(buffer_in, 1, len, glob->stream);
-}
-
-#define WRITE_BUFFER(s) \
-for (i = len - 1; i >= 0; i--) { \
-  x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \
-  Ebml_Write(glob, &x, 1); \
-}
-
-void Ebml_Serialize(struct EbmlGlobal *glob,
-                    const void *buffer_in,
-                    int buffer_size,
-                    unsigned long len) {
-  char x;
-  int i;
-
-  /* buffer_size:
-   * 1 - int8_t;
-   * 2 - int16_t;
-   * 3 - int32_t;
-   * 4 - int64_t;
-   */
-  switch (buffer_size) {
-    case 1:
-      WRITE_BUFFER(int8_t)
-      break;
-    case 2:
-      WRITE_BUFFER(int16_t)
-      break;
-    case 4:
-      WRITE_BUFFER(int32_t)
-      break;
-    case 8:
-      WRITE_BUFFER(int64_t)
-      break;
-    default:
-      break;
-  }
-}
-#undef WRITE_BUFFER
-
-/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit
- * one, but not a 32 bit one.
- */
-static void Ebml_SerializeUnsigned32(struct EbmlGlobal *glob,
-                                     unsigned int class_id,
-                                     uint64_t ui) {
-  const unsigned char sizeSerialized = 4 | 0x80;
-  Ebml_WriteID(glob, class_id);
-  Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
-  Ebml_Serialize(glob, &ui, sizeof(ui), 4);
-}
-
-static void Ebml_StartSubElement(struct EbmlGlobal *glob,
-                                 EbmlLoc *ebmlLoc,
-                                 unsigned int class_id) {
-  const uint64_t kEbmlUnknownLength = LITERALU64(0x01FFFFFF, 0xFFFFFFFF);
-  Ebml_WriteID(glob, class_id);
-  *ebmlLoc = ftello(glob->stream);
-  Ebml_Serialize(glob, &kEbmlUnknownLength, sizeof(kEbmlUnknownLength), 8);
-}
-
-static void Ebml_EndSubElement(struct EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
-  off_t pos;
-  uint64_t size;
-
-  /* Save the current stream pointer. */
-  pos = ftello(glob->stream);
-
-  /* Calculate the size of this element. */
-  size = pos - *ebmlLoc - 8;
-  size |= LITERALU64(0x01000000, 0x00000000);
-
-  /* Seek back to the beginning of the element and write the new size. */
-  fseeko(glob->stream, *ebmlLoc, SEEK_SET);
-  Ebml_Serialize(glob, &size, sizeof(size), 8);
-
-  /* Reset the stream pointer. */
-  fseeko(glob->stream, pos, SEEK_SET);
-}
-
-void write_webm_seek_element(struct EbmlGlobal *ebml,
-                             unsigned int id,
-                             off_t pos) {
-  uint64_t offset = pos - ebml->position_reference;
-  EbmlLoc start;
-  Ebml_StartSubElement(ebml, &start, Seek);
-  Ebml_SerializeBinary(ebml, SeekID, id);
-  Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
-  Ebml_EndSubElement(ebml, &start);
-}
-
-void write_webm_seek_info(struct EbmlGlobal *ebml) {
-  off_t pos;
-  EbmlLoc start;
-  EbmlLoc startInfo;
-  uint64_t frame_time;
-  char version_string[64];
-
-  /* Save the current stream pointer. */
-  pos = ftello(ebml->stream);
-
-  if (ebml->seek_info_pos)
-    fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
-  else
-    ebml->seek_info_pos = pos;
-
-  Ebml_StartSubElement(ebml, &start, SeekHead);
-  write_webm_seek_element(ebml, Tracks, ebml->track_pos);
-  write_webm_seek_element(ebml, Cues, ebml->cue_pos);
-  write_webm_seek_element(ebml, Info, ebml->segment_info_pos);
-  Ebml_EndSubElement(ebml, &start);
-
-  /* Create and write the Segment Info. */
-  if (ebml->debug) {
-    strcpy(version_string, "vpxenc");
-  } else {
-    strcpy(version_string, "vpxenc ");
-    strncat(version_string,
-            vpx_codec_version_str(),
-            sizeof(version_string) - 1 - strlen(version_string));
-  }
-
-  frame_time = (uint64_t)1000 * ebml->framerate.den
-               / ebml->framerate.num;
-  ebml->segment_info_pos = ftello(ebml->stream);
-  Ebml_StartSubElement(ebml, &startInfo, Info);
-  Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
-  Ebml_SerializeFloat(ebml, Segment_Duration,
-                      (double)(ebml->last_pts_ms + frame_time));
-  Ebml_SerializeString(ebml, 0x4D80, version_string);
-  Ebml_SerializeString(ebml, 0x5741, version_string);
-  Ebml_EndSubElement(ebml, &startInfo);
-}
-
-void write_webm_file_header(struct EbmlGlobal *glob,
-                            const vpx_codec_enc_cfg_t *cfg,
-                            const struct vpx_rational *fps,
-                            stereo_format_t stereo_fmt,
-                            unsigned int fourcc) {
-  EbmlLoc start;
-  EbmlLoc trackStart;
-  EbmlLoc videoStart;
-  unsigned int trackNumber = 1;
-  uint64_t trackID = 0;
-  unsigned int pixelWidth = cfg->g_w;
-  unsigned int pixelHeight = cfg->g_h;
-
-  /* Write the EBML header. */
-  Ebml_StartSubElement(glob, &start, EBML);
-  Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
-  Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1);
-  Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4);
-  Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8);
-  Ebml_SerializeString(glob, DocType, "webm");
-  Ebml_SerializeUnsigned(glob, DocTypeVersion, 2);
-  Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2);
-  Ebml_EndSubElement(glob, &start);
-
-  /* Open and begin writing the segment element. */
-  Ebml_StartSubElement(glob, &glob->startSegment, Segment);
-  glob->position_reference = ftello(glob->stream);
-  glob->framerate = *fps;
-  write_webm_seek_info(glob);
-
-  /* Open and write the Tracks element. */
-  glob->track_pos = ftello(glob->stream);
-  Ebml_StartSubElement(glob, &trackStart, Tracks);
-
-  /* Open and write the Track entry. */
-  Ebml_StartSubElement(glob, &start, TrackEntry);
-  Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
-  glob->track_id_pos = ftello(glob->stream);
-  Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
-  Ebml_SerializeUnsigned(glob, TrackType, 1);
-  Ebml_SerializeString(glob, CodecID,
-                       fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
-  Ebml_StartSubElement(glob, &videoStart, Video);
-  Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
-  Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
-  Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt);
-  Ebml_EndSubElement(glob, &videoStart);
-
-  /* Close Track entry. */
-  Ebml_EndSubElement(glob, &start);
-
-  /* Close Tracks element. */
-  Ebml_EndSubElement(glob, &trackStart);
-
-  /* Segment element remains open. */
-}
-
-void write_webm_block(struct EbmlGlobal *glob,
-                      const vpx_codec_enc_cfg_t *cfg,
-                      const vpx_codec_cx_pkt_t *pkt) {
-  unsigned int block_length;
-  unsigned char track_number;
-  uint16_t block_timecode = 0;
-  unsigned char flags;
-  int64_t pts_ms;
-  int start_cluster = 0, is_keyframe;
-
-  /* Calculate the PTS of this frame in milliseconds. */
-  pts_ms = pkt->data.frame.pts * 1000
-           * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
-
-  if (pts_ms <= glob->last_pts_ms)
-    pts_ms = glob->last_pts_ms + 1;
-
-  glob->last_pts_ms = pts_ms;
-
-  /* Calculate the relative time of this block. */
-  if (pts_ms - glob->cluster_timecode > SHRT_MAX)
-    start_cluster = 1;
-  else
-    block_timecode = (uint16_t)pts_ms - glob->cluster_timecode;
-
-  is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
-  if (start_cluster || is_keyframe) {
-    if (glob->cluster_open)
-      Ebml_EndSubElement(glob, &glob->startCluster);
-
-    /* Open the new cluster. */
-    block_timecode = 0;
-    glob->cluster_open = 1;
-    glob->cluster_timecode = (uint32_t)pts_ms;
-    glob->cluster_pos = ftello(glob->stream);
-    Ebml_StartSubElement(glob, &glob->startCluster, Cluster);
-    Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);
-
-    /* Save a cue point if this is a keyframe. */
-    if (is_keyframe) {
-      struct cue_entry *cue, *new_cue_list;
-
-      new_cue_list = realloc(glob->cue_list,
-                             (glob->cues + 1) * sizeof(struct cue_entry));
-      if (new_cue_list)
-        glob->cue_list = new_cue_list;
-      else
-        fatal("Failed to realloc cue list.");
-
-      cue = &glob->cue_list[glob->cues];
-      cue->time = glob->cluster_timecode;
-      cue->loc = glob->cluster_pos;
-      glob->cues++;
-    }
-  }
-
-  /* Write the Simple Block. */
-  Ebml_WriteID(glob, SimpleBlock);
-
-  block_length = (unsigned int)pkt->data.frame.sz + 4;
-  block_length |= 0x10000000;
-  Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);
-
-  track_number = 1;
-  track_number |= 0x80;
-  Ebml_Write(glob, &track_number, 1);
-
-  Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2);
-
-  flags = 0;
-  if (is_keyframe)
-    flags |= 0x80;
-  if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
-    flags |= 0x08;
-  Ebml_Write(glob, &flags, 1);
-
-  Ebml_Write(glob, pkt->data.frame.buf, (unsigned int)pkt->data.frame.sz);
-}
-
-void write_webm_file_footer(struct EbmlGlobal *glob, int hash) {
-  EbmlLoc start_cues;
-  EbmlLoc start_cue_point;
-  EbmlLoc start_cue_tracks;
-  unsigned int i;
-
-  if (glob->cluster_open)
-    Ebml_EndSubElement(glob, &glob->startCluster);
-
-  glob->cue_pos = ftello(glob->stream);
-  Ebml_StartSubElement(glob, &start_cues, Cues);
-
-  for (i = 0; i < glob->cues; i++) {
-    struct cue_entry *cue = &glob->cue_list[i];
-    Ebml_StartSubElement(glob, &start_cue_point, CuePoint);
-    Ebml_SerializeUnsigned(glob, CueTime, cue->time);
-
-    Ebml_StartSubElement(glob, &start_cue_tracks, CueTrackPositions);
-    Ebml_SerializeUnsigned(glob, CueTrack, 1);
-    Ebml_SerializeUnsigned64(glob, CueClusterPosition,
-                             cue->loc - glob->position_reference);
-    Ebml_EndSubElement(glob, &start_cue_tracks);
-
-    Ebml_EndSubElement(glob, &start_cue_point);
-  }
-
-  Ebml_EndSubElement(glob, &start_cues);
-
-  /* Close the Segment. */
-  Ebml_EndSubElement(glob, &glob->startSegment);
-
-  /* Patch up the seek info block. */
-  write_webm_seek_info(glob);
-
-  /* Patch up the track id. */
-  fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
-  Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
-
-  fseeko(glob->stream, 0, SEEK_END);
-}
diff --git a/webmenc.cc b/webmenc.cc
new file mode 100644
index 0000000..a0e542b
--- /dev/null
+++ b/webmenc.cc
@@ -0,0 +1,87 @@
+/*
+ *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "./webmenc.h"
+
+#include <string>
+
+#include "third_party/libwebm/mkvmuxer.hpp"
+#include "third_party/libwebm/mkvmuxerutil.hpp"
+#include "third_party/libwebm/mkvwriter.hpp"
+
+namespace {
+const uint64_t kDebugTrackUid = 0xDEADBEEF;
+const int kVideoTrackNumber = 1;
+}  // namespace
+
+void write_webm_file_header(struct EbmlGlobal *glob,
+                            const vpx_codec_enc_cfg_t *cfg,
+                            const struct vpx_rational *fps,
+                            stereo_format_t stereo_fmt,
+                            unsigned int fourcc) {
+  mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(glob->stream);
+  mkvmuxer::Segment *const segment = new mkvmuxer::Segment();
+  segment->Init(writer);
+  segment->set_mode(mkvmuxer::Segment::kFile);
+  segment->OutputCues(true);
+
+  mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo();
+  const uint64_t kTimecodeScale = 1000000;
+  info->set_timecode_scale(kTimecodeScale);
+  std::string version = "vpxenc";
+  if (!glob->debug) {
+    version.append(std::string(" ") + vpx_codec_version_str());
+  }
+  info->set_writing_app(version.c_str());
+
+  const uint64_t video_track_id =
+      segment->AddVideoTrack(static_cast<int>(cfg->g_w),
+                             static_cast<int>(cfg->g_h),
+                             kVideoTrackNumber);
+  mkvmuxer::VideoTrack* const video_track =
+      static_cast<mkvmuxer::VideoTrack*>(
+          segment->GetTrackByNumber(video_track_id));
+  video_track->SetStereoMode(stereo_fmt);
+  video_track->set_codec_id(fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
+  if (glob->debug) {
+    video_track->set_uid(kDebugTrackUid);
+  }
+  glob->writer = writer;
+  glob->segment = segment;
+}
+
+void write_webm_block(struct EbmlGlobal *glob,
+                      const vpx_codec_enc_cfg_t *cfg,
+                      const vpx_codec_cx_pkt_t *pkt) {
+  mkvmuxer::Segment *const segment =
+      reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
+  int64_t pts_ns = pkt->data.frame.pts * 1000000000ll *
+                   cfg->g_timebase.num / cfg->g_timebase.den;
+  if (pts_ns <= glob->last_pts_ns)
+    pts_ns = glob->last_pts_ns + 1000000;
+  glob->last_pts_ns = pts_ns;
+
+  segment->AddFrame(static_cast<uint8_t*>(pkt->data.frame.buf),
+                    pkt->data.frame.sz,
+                    kVideoTrackNumber,
+                    pts_ns,
+                    pkt->data.frame.flags & VPX_FRAME_IS_KEY);
+}
+
+void write_webm_file_footer(struct EbmlGlobal *glob) {
+  mkvmuxer::MkvWriter *const writer =
+      reinterpret_cast<mkvmuxer::MkvWriter*>(glob->writer);
+  mkvmuxer::Segment *const segment =
+      reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
+  segment->Finalize();
+  delete segment;
+  delete writer;
+  glob->writer = NULL;
+  glob->segment = NULL;
+}
diff --git a/webmenc.h b/webmenc.h
index 362aa89..0ac606b 100644
--- a/webmenc.h
+++ b/webmenc.h
@@ -13,13 +13,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#if defined(_MSC_VER)
-/* MSVS doesn't define off_t */
-typedef __int64 off_t;
-#else
-#include <stdint.h>
-#endif
-
 #include "tools_common.h"
 #include "vpx/vpx_encoder.h"
 
@@ -27,40 +20,13 @@
 extern "C" {
 #endif
 
-typedef off_t EbmlLoc;
-
-struct cue_entry {
-  unsigned int time;
-  uint64_t loc;
-};
-
+/* TODO(vigneshv): Rename this struct */
 struct EbmlGlobal {
   int debug;
-
   FILE *stream;
-  int64_t last_pts_ms;
-  vpx_rational_t framerate;
-
-  /* These pointers are to the start of an element */
-  off_t position_reference;
-  off_t seek_info_pos;
-  off_t segment_info_pos;
-  off_t track_pos;
-  off_t cue_pos;
-  off_t cluster_pos;
-
-  /* This pointer is to a specific element to be serialized */
-  off_t track_id_pos;
-
-  /* These pointers are to the size field of the element */
-  EbmlLoc startSegment;
-  EbmlLoc startCluster;
-
-  uint32_t cluster_timecode;
-  int cluster_open;
-
-  struct cue_entry *cue_list;
-  unsigned int cues;
+  int64_t last_pts_ns;
+  void *writer;
+  void *segment;
 };
 
 /* Stereo 3D packed frame format */
@@ -72,10 +38,6 @@
   STEREO_FORMAT_RIGHT_LEFT = 11
 } stereo_format_t;
 
-void write_webm_seek_element(struct EbmlGlobal *ebml,
-                             unsigned int id,
-                             off_t pos);
-
 void write_webm_file_header(struct EbmlGlobal *glob,
                             const vpx_codec_enc_cfg_t *cfg,
                             const struct vpx_rational *fps,
@@ -86,7 +48,7 @@
                       const vpx_codec_enc_cfg_t *cfg,
                       const vpx_codec_cx_pkt_t *pkt);
 
-void write_webm_file_footer(struct EbmlGlobal *glob, int hash);
+void write_webm_file_footer(struct EbmlGlobal *glob);
 
 #ifdef __cplusplus
 }  // extern "C"