CWG-F142: Extend the MV range from 15bits to 17bits

1) MV range is extended to 17bits;
2) Encoder control flag to enable high or low motion
   Motion search window would be adjusted based on high or low motion control flag

STATS_CHANGED
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h
index 582b7f3..44c44c0 100644
--- a/aom/aom_encoder.h
+++ b/aom/aom_encoder.h
@@ -321,6 +321,12 @@
    */
   unsigned int enable_mv_traj;
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  /*!\brief Enable a large motion search window (Encoder only)
+   *
+   */
+  unsigned int enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   /*!\brief enable block adaptive weighted prediction
    *
    */
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 5a1049f..7b5f613 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -448,6 +448,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   &g_av1_codec_arg_defs.enable_mv_traj,
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  &g_av1_codec_arg_defs.enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
   &g_av1_codec_arg_defs.enable_bawp,
 #if CONFIG_ENABLE_MHCCP
   &g_av1_codec_arg_defs.enable_mhccp,
@@ -663,6 +666,12 @@
   config->enable_extended_sdp = 1;
   config->enable_mrls = 1;
   config->enable_tip = 1;
+#if CONFIG_TMVP_SIMPLIFICATIONS_F085
+  config->enable_mv_traj = 1;
+#endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  config->enable_high_motion = 0;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   config->enable_bawp = 1;
   config->enable_cwp = 1;
 #if CONFIG_D071_IMP_MSK_BLD
@@ -1626,6 +1635,10 @@
   fprintf(stdout, "                               : MV traj (%d)\n",
           encoder_cfg->enable_mv_traj);
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  fprintf(stdout, "                               : HighMotion (%d)\n",
+          encoder_cfg->enable_high_motion);
+#endif  // CONFIG_MV_RANGE_EXTENSION
   fprintf(stdout, "                               : BAWP (%d)\n",
           encoder_cfg->enable_bawp);
   fprintf(stdout, "                               : CWP (%d)\n",
diff --git a/av1/arg_defs.c b/av1/arg_defs.c
index accc4f4..6d61c91 100644
--- a/av1/arg_defs.c
+++ b/av1/arg_defs.c
@@ -433,7 +433,11 @@
                             "(0: disable MV traj tracking, "
                             " 1: enable MV traj tracking (default))"),
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
-
+#if CONFIG_MV_RANGE_EXTENSION
+  .enable_high_motion = ARG_DEF(NULL, "enable-high-motion", 1,
+                                "Enable a large motion search window"
+                                "(0: false (default), 1: true"),
+#endif  // CONFIG_MV_RANGE_EXTENSION
   .enable_bawp = ARG_DEF(NULL, "enable-bawp", 1,
                          "Enable block adaptive weighted prediction (BAWP)"
                          "(0: false, 1: true (default))"),
diff --git a/av1/arg_defs.h b/av1/arg_defs.h
index d68b26b..0dddfd2 100644
--- a/av1/arg_defs.h
+++ b/av1/arg_defs.h
@@ -162,6 +162,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   arg_def_t enable_mv_traj;
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  arg_def_t enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   arg_def_t enable_bawp;
   arg_def_t enable_cwp;
 #if CONFIG_D071_IMP_MSK_BLD
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 617e588..59962de 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -131,8 +131,11 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   int enable_mv_traj;  // enable MV trajectory tracking
 #endif                 // CONFIG_TMVP_SIMPLIFICATIONS_F085
-  int enable_bawp;     // enable block adaptive weighted prediction
-  int enable_cwp;      // enable compound weighted prediction
+#if CONFIG_MV_RANGE_EXTENSION
+  int enable_high_motion;  // Enable a large motion search window
+#endif                     // CONFIG_MV_RANGE_EXTENSION
+  int enable_bawp;         // enable block adaptive weighted prediction
+  int enable_cwp;          // enable compound weighted prediction
 #if CONFIG_D071_IMP_MSK_BLD
   int enable_imp_msk_bld;
 #endif  // CONFIG_D071_IMP_MSK_BLD
@@ -489,6 +492,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   1,    // enable mv trajectory tracking
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  0,    // enable a large motion search window
+#endif  // CONFIG_MV_RANGE_EXTENSION
   1,    // enable block adaptive weighted prediction (BAWP)
   1,    // enable compound weighted prediction (CWP)
 #if CONFIG_D071_IMP_MSK_BLD
@@ -1022,6 +1028,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   cfg->enable_mv_traj = extra_cfg->enable_mv_traj;
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = extra_cfg->enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   cfg->enable_bawp = extra_cfg->enable_bawp;
   cfg->enable_cwp = extra_cfg->enable_cwp;
 #if CONFIG_D071_IMP_MSK_BLD
@@ -1165,6 +1174,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
   extra_cfg->enable_mv_traj = cfg->enable_mv_traj;
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  extra_cfg->enable_high_motion = cfg->enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   extra_cfg->enable_bawp = cfg->enable_bawp;
   extra_cfg->enable_cwp = cfg->enable_cwp;
 #if CONFIG_D071_IMP_MSK_BLD
@@ -1584,6 +1596,10 @@
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
   }
 
+#if CONFIG_MV_RANGE_EXTENSION
+  tool_cfg->enable_high_motion = extra_cfg->enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
 #if CONFIG_FRAME_HEADER_SIGNAL_OPT
   if (extra_cfg->enable_order_hint) {
     tool_cfg->enable_opfl_refine = extra_cfg->enable_opfl_refine;
@@ -4195,6 +4211,11 @@
                               err_string)) {
     extra_cfg.enable_mv_traj = arg_parse_int_helper(&arg, err_string);
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  } else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.enable_high_motion,
+                              argv, err_string)) {
+    extra_cfg.enable_high_motion = arg_parse_int_helper(&arg, err_string);
+#endif  // CONFIG_MV_RANGE_EXTENSION
   } else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.enable_bawp, argv,
                               err_string)) {
     extra_cfg.enable_bawp = arg_parse_int_helper(&arg, err_string);
@@ -4782,6 +4803,9 @@
 #if CONFIG_TMVP_SIMPLIFICATIONS_F085
         1,  // MV traj
 #endif      // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+        0,  // enable_high_motion
+#endif      // CONFIG_MV_RANGE_EXTENSION
         1,   1,
 #if CONFIG_D071_IMP_MSK_BLD
         1,
diff --git a/av1/common/entropy.c b/av1/common/entropy.c
index 1e08b78..659797d 100644
--- a/av1/common/entropy.c
+++ b/av1/common/entropy.c
@@ -121,12 +121,30 @@
     int num_mv_class_0, num_mv_class_1;
     split_num_shell_class(num_mv_class, &num_mv_class_0, &num_mv_class_1);
     RESET_CDF_COUNTER(nmv->joint_shell_class_cdf_0[prec], num_mv_class_0);
-    RESET_CDF_COUNTER(nmv->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      RESET_CDF_COUNTER(nmv->joint_shell_class_cdf_1[prec], num_mv_class_1 - 1);
+      RESET_CDF_COUNTER(nmv->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      RESET_CDF_COUNTER(nmv->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
   for (int prec = 0; prec < NUM_MV_PRECISIONS; prec++) {
     int num_mv_class = get_default_num_shell_class(prec);
-    RESET_CDF_COUNTER(nmv->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      RESET_CDF_COUNTER(nmv->joint_shell_class_cdf[prec], num_mv_class - 1);
+      RESET_CDF_COUNTER(nmv->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      RESET_CDF_COUNTER(nmv->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   RESET_CDF_COUNTER(nmv->shell_offset_low_class_cdf, 2);
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 8944c9d..ac17f6e 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -7475,15 +7475,39 @@
     CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf_0[prec],
                            nmv_tr->joint_shell_class_cdf_0[prec],
                            num_mv_class_0);
-    CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
-                           nmv_tr->joint_shell_class_cdf_1[prec],
-                           num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                             nmv_tr->joint_shell_class_cdf_1[prec],
+                             num_mv_class_1 - 1);
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                             nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                             nmv_tr->joint_shell_class_cdf_1[prec],
+                             num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
   for (int prec = 0; prec < NUM_MV_PRECISIONS; prec++) {
     int num_mv_class = get_default_num_shell_class(prec);
-    CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
-                           nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                             nmv_tr->joint_shell_class_cdf[prec],
+                             num_mv_class - 1);
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                             nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      CUMULATIVE_AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                             nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   CUMULATIVE_AVERAGE_CDF(nmv_left->shell_offset_low_class_cdf,
@@ -7973,12 +7997,30 @@
     int num_mv_class_0, num_mv_class_1;
     split_num_shell_class(num_mv_class, &num_mv_class_0, &num_mv_class_1);
     SHIFT_CDF(nmv_ptr->joint_shell_class_cdf_0[prec], num_mv_class_0);
-    SHIFT_CDF(nmv_ptr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      SHIFT_CDF(nmv_ptr->joint_shell_class_cdf_1[prec], num_mv_class_1 - 1);
+      SHIFT_CDF(nmv_ptr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      SHIFT_CDF(nmv_ptr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
   for (int prec = 0; prec < NUM_MV_PRECISIONS; prec++) {
     int num_mv_class = get_default_num_shell_class(prec);
-    SHIFT_CDF(nmv_ptr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      SHIFT_CDF(nmv_ptr->joint_shell_class_cdf[prec], num_mv_class - 1);
+      SHIFT_CDF(nmv_ptr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      SHIFT_CDF(nmv_ptr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   SHIFT_CDF(nmv_ptr->shell_offset_low_class_cdf, 2);
@@ -8328,14 +8370,36 @@
     split_num_shell_class(num_mv_class, &num_mv_class_0, &num_mv_class_1);
     AVERAGE_CDF(nmv_left->joint_shell_class_cdf_0[prec],
                 nmv_tr->joint_shell_class_cdf_0[prec], num_mv_class_0);
-    AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
-                nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                  nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1 - 1);
+      AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                  nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                  nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
   for (int prec = 0; prec < NUM_MV_PRECISIONS; prec++) {
     int num_mv_class = get_default_num_shell_class(prec);
-    AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
-                nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                  nmv_tr->joint_shell_class_cdf[prec], num_mv_class - 1);
+      AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                  nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                  nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   AVERAGE_CDF(nmv_left->shell_offset_low_class_cdf,
diff --git a/av1/common/entropymv.c b/av1/common/entropymv.c
index 6281c08..13e4562 100644
--- a/av1/common/entropymv.c
+++ b/av1/common/entropymv.c
@@ -19,6 +19,26 @@
 #else
 #if CONFIG_REDUCE_SYMBOL_SIZE
   { AOM_CDF2(24576), 0 },  // joint_shell_set_cdf
+#if CONFIG_MV_RANGE_EXTENSION
+  {
+      { AOM_CDF5(6847, 15990, 24873, 32100), 0 },
+      { AOM_CDF6(8452, 19730, 26138, 30154, 32100), 0 },
+      { AOM_CDF6(6553, 13106, 19659, 26212, 32100), 0 },
+      { AOM_CDF7(5062, 12676, 19127, 24565, 29511, 32100), 0 },
+      { AOM_CDF7(4553, 16572, 24700, 28964, 31428, 32100), 0 },
+      { AOM_CDF8(2750, 12194, 20615, 25661, 28862, 31157, 32100), 0 },
+      { AOM_CDF8(7886, 19300, 26400, 29900, 31400, 32100, 32740), 0 },
+  },  // joint_shell_class_cdf_0
+  {
+      { AOM_CDF6(17356, 28590, 32415, 32740, 32760), 0 },
+      { AOM_CDF6(21505, 30000, 31700, 31819, 32100), 0 },
+      { AOM_CDF7(5461, 10922, 16383, 21844, 27305, 32100), 0 },
+      { AOM_CDF7(21567, 30194, 32730, 32755, 32760, 32764), 0 },
+      { AOM_CDF8(20234, 28560, 30530, 31246, 31694, 32141, 32740), 0 },
+      { AOM_CDF8(18126, 26500, 30750, 32100, 32185, 32400, 32740), 0 },
+      { AOM_CDF8(16384, 24576, 28672, 29696, 29970, 30244, 30518), 0 },
+  },  // joint_shell_class_cdf_1
+#else
   {
       { AOM_CDF4(6847, 15990, 24873), 0 },
       { AOM_CDF5(8452, 19730, 26138, 30154), 0 },
@@ -37,8 +57,32 @@
       { AOM_CDF7(18126, 26500, 30750, 32100, 32185, 32400), 0 },
       { AOM_CDF8(16384, 24576, 28672, 29696, 29970, 30244, 30518), 0 },
   },  // joint_shell_class_cdf_1
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #else
   {
+#if CONFIG_MV_RANGE_EXTENSION
+      { AOM_CDF11(4820, 11253, 17504, 23064, 28204, 31531, 32664, 32760, 32762,
+                  32764),
+        30 },
+      { AOM_CDF12(7955, 18569, 24600, 28379, 30839, 32105, 32619, 32753, 32760,
+                  32762, 32764),
+        7 },
+      { AOM_CDF13(2978, 5956, 8934, 11912, 14890, 17868, 20846, 23824, 26802,
+                  29780, 30839, 32760),
+        0 },
+      { AOM_CDF14(4710, 11795, 17797, 22857, 27459, 30489, 31939, 32543, 32730,
+                  32755, 32760, 32762, 32764),
+        0 },
+      { AOM_CDF15(4452, 16202, 24148, 28317, 30726, 32036, 32494, 32680, 32724,
+                  32740, 32750, 32760, 32762, 32764),
+        1 },
+      { AOM_CDF16(2621, 11620, 19645, 24454, 27504, 29691, 31226, 32079, 32497,
+                  32684, 32750, 32754, 32760, 32762, 32764),
+        1 },
+      { AOM_CDF16(7771, 19161, 26258, 29752, 31259, 31926, 32289, 32539, 32668,
+                  32738, 32752, 32756, 32760, 32762, 32764),
+        75 },
+#else
       { AOM_CDF9(4820, 11253, 17504, 23064, 28204, 31531, 32664, 32760), 30 },
       { AOM_CDF10(7955, 18569, 24600, 28379, 30839, 32105, 32619, 32753, 32760),
         7 },
@@ -57,8 +101,14 @@
       { AOM_CDF15(7771, 19161, 26258, 29752, 31259, 31926, 32289, 32539, 32668,
                   32738, 32752, 32756, 32760, 32764),
         75 },
+#endif  // CONFIG_MV_RANGE_EXTENSION
   },  // joint_shell_class_cdf
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
+
+#if CONFIG_MV_RANGE_EXTENSION
+  { AOM_CDF2(16384), 0 },  // joint_shell_last_two_classes_cdf
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
   {
       { AOM_CDF2(3268), 1 },
       { AOM_CDF2(17309), 75 },
@@ -89,6 +139,10 @@
       { AOM_CDF2(29343), 50 },
       { AOM_CDF2(16384), 0 },
       { AOM_CDF2(16384), 0 },
+#if CONFIG_MV_RANGE_EXTENSION
+      { AOM_CDF2(16384), 0 },
+      { AOM_CDF2(16384), 0 },
+#endif  // CONFIG_MV_RANGE_EXTENSION
   } },  // shell_offset_other_class_cdf
 #endif  // !CONFIG_CTX_MV_SHELL_OFFSET_OTHER
   {
@@ -106,8 +160,35 @@
   { AOM_CDF4(4, 19409, 32748), 1 },  // amvd_joints_cdf
   {
       {
-
 #if !CONFIG_VQ_MVD_CODING
+#if CONFIG_MV_RANGE_EXTENSION
+          {
+              { AOM_CDF11(9045, 14234, 20059, 25670, 29656, 31856, 32661, 32708,
+                          32710, 32712),
+                76 },
+              { AOM_CDF12(13873, 20198, 26490, 29945, 31547, 32216, 32659,
+                          32704, 32708, 32710, 32712),
+                1 },
+              { AOM_CDF13(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831,
+                          26810, 29789, 31010, 32012),
+                0 },
+              { AOM_CDF13(13705, 18604, 23447, 27806, 30775, 32116, 32589,
+                          32700, 32704, 32708, 32710, 32712),
+                75 },
+              { AOM_CDF13(26824, 30545, 31965, 32526, 32676, 32708, 32712,
+                          32716, 32720, 32724, 32726, 32728),
+                75 },
+              { AOM_CDF13(25936, 28131, 29757, 31161, 32142, 32545, 32698,
+                          32702, 32706, 32710, 32712, 32714),
+                75 },
+              { AOM_CDF13(32029, 32523, 32665, 32716, 32720, 32724, 32728,
+                          32732, 32736, 32740, 32742, 32744),
+                75 },
+          },  // classes_cdf
+          { AOM_CDF13(28615, 31027, 32182, 32608, 32712, 32716, 32720, 32724,
+                      32728, 32732, 32734, 32736),
+            0 },  // amvd_classes_cdf
+#else
           {
               { AOM_CDF9(9045, 14234, 20059, 25670, 29656, 31856, 32661, 32708),
                 76 },
@@ -129,12 +210,14 @@
               { AOM_CDF11(32029, 32523, 32665, 32716, 32720, 32724, 32728,
                           32732, 32736, 32740),
                 75 },
-          },
+          },  // classes_cdf
           { AOM_CDF11(28615, 31027, 32182, 32608, 32712, 32716, 32720, 32724,
                       32728, 32732),
-            0 },
+            0 },  // amvd_classes_cdf
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #else
-          { AOM_CDF8(7804, 11354, 12626, 18581, 24598, 29144, 31608), 1 },
+          { AOM_CDF8(7804, 11354, 12626, 18581, 24598, 29144, 31608),
+            1 },  // amvd_indices_cdf
 #endif  // !CONFIG_VQ_MVD_CODING
 
 #if !CONFIG_VQ_MVD_CODING
@@ -149,20 +232,20 @@
                   { AOM_CDF2(11921), 1 },
                   { AOM_CDF2(12406), 1 },
               },
-          },
+          },  // class0_fp_cdf
           {
               { AOM_CDF2(18429), 90 },
               { AOM_CDF2(15625), 0 },
               { AOM_CDF2(17117), 75 },
-          },
-#endif  // !CONFIG_VQ_MVD_CODING
+          },  // fp_cdf
+#endif        // !CONFIG_VQ_MVD_CODING
 #if !CONFIG_MVD_CDF_REDUCTION
-          { AOM_CDF2(16024), 0 },
-#endif  //! CONFIG_MVD_CDF_REDUCTION
+          { AOM_CDF2(16024), 0 },  // sign_cdf
+#endif                             //! CONFIG_MVD_CDF_REDUCTION
 #if !CONFIG_VQ_MVD_CODING
-          { AOM_CDF2(25929), 90 },
-          { AOM_CDF2(11557), 84 },
-          { AOM_CDF2(26908), 75 },
+          { AOM_CDF2(25929), 90 },  // class0_hp_cdf
+          { AOM_CDF2(11557), 84 },  // hp_cdf
+          { AOM_CDF2(26908), 75 },  // class0_cdf
           {
               { AOM_CDF2(18078), 124 },
               { AOM_CDF2(18254), 124 },
@@ -174,12 +257,43 @@
               { AOM_CDF2(26291), 5 },
               { AOM_CDF2(30118), 100 },
               { AOM_CDF2(16384), 0 },
-          },
-#endif  // !CONFIG_VQ_MVD_CODING
+#if CONFIG_MV_RANGE_EXTENSION
+              { AOM_CDF2(16384), 0 },
+              { AOM_CDF2(16384), 0 },
+#endif        // CONFIG_MV_RANGE_EXTENSION
+          },  // bits_cdf
+#endif        // !CONFIG_VQ_MVD_CODING
       },
       {
-
 #if !CONFIG_VQ_MVD_CODING
+#if CONFIG_MV_RANGE_EXTENSION
+          {
+              { AOM_CDF11(8910, 13492, 19259, 24751, 28899, 31567, 32600, 32708,
+                          32710, 32712),
+                76 },
+              { AOM_CDF12(15552, 21454, 26682, 29649, 31333, 32161, 32591,
+                          32704, 32708, 32710, 32712, 32714, 32716),
+                76 },
+              { AOM_CDF13(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831,
+                          26810, 29789, 31010, 32012),
+                0 },
+              { AOM_CDF13(12301, 18138, 23549, 27708, 30501, 31883, 32463,
+                          32682, 32696, 32700, 32704, 32708),
+                75 },
+              { AOM_CDF13(26132, 29614, 31375, 32280, 32639, 32708, 32712,
+                          32716, 32720, 32724, 32726, 32728),
+                75 },
+              { AOM_CDF13(25359, 28443, 30284, 31515, 32242, 32565, 32693,
+                          32700, 32704, 32708, 32710, 32712),
+                75 },
+              { AOM_CDF13(31842, 32400, 32592, 32694, 32712, 32716, 32720,
+                          32724, 32728, 32732, 32734, 32738),
+                75 },
+          },  // classes_cdf
+          { AOM_CDF13(29563, 31499, 32361, 32658, 32712, 32716, 32720, 32724,
+                      32728, 32732),
+            0 },  // amvd_classes_cdf
+#else
           {
               { AOM_CDF9(8910, 13492, 19259, 24751, 28899, 31567, 32600, 32708),
                 76 },
@@ -201,12 +315,14 @@
               { AOM_CDF11(31842, 32400, 32592, 32694, 32712, 32716, 32720,
                           32724, 32728, 32732),
                 75 },
-          },
+          },  // classes_cdf
           { AOM_CDF11(29563, 31499, 32361, 32658, 32712, 32716, 32720, 32724,
                       32728, 32732),
-            0 },
+            0 },  // amvd_classes_cdf
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #else
-          { AOM_CDF8(7392, 11106, 12422, 18167, 24480, 29230, 31714), 1 },
+          { AOM_CDF8(7392, 11106, 12422, 18167, 24480, 29230, 31714),
+            1 },  // amvd_indices_cdf
 #endif  // !CONFIG_VQ_MVD_CODING
 #if !CONFIG_VQ_MVD_CODING
           {
@@ -220,20 +336,20 @@
                   { AOM_CDF2(12278), 0 },
                   { AOM_CDF2(11913), 1 },
               },
-          },
+          },  // class0_fp_cdf
           {
               { AOM_CDF2(14462), 75 },
               { AOM_CDF2(11379), 75 },
               { AOM_CDF2(6857), 0 },
-          },
-#endif  // !CONFIG_VQ_MVD_CODING
+          },  // fp_cdf
+#endif        // !CONFIG_VQ_MVD_CODING
 #if !CONFIG_MVD_CDF_REDUCTION
-          { AOM_CDF2(16302), 75 },
-#endif  //! CONFIG_MVD_CDF_REDUCTION
+          { AOM_CDF2(16302), 75 },  // sign_cdf
+#endif                              //! CONFIG_MVD_CDF_REDUCTION
 #if !CONFIG_VQ_MVD_CODING
-          { AOM_CDF2(24896), 75 },
-          { AOM_CDF2(16355), 119 },
-          { AOM_CDF2(26968), 75 },
+          { AOM_CDF2(24896), 75 },   // class0_hp_cdf
+          { AOM_CDF2(16355), 119 },  // hp_cdf
+          { AOM_CDF2(26968), 75 },   // class0_cdf
           {
               { AOM_CDF2(19196), 124 },
               { AOM_CDF2(17877), 124 },
@@ -245,8 +361,12 @@
               { AOM_CDF2(23432), 77 },
               { AOM_CDF2(29155), 0 },
               { AOM_CDF2(16384), 0 },
-          },
-#endif  // !CONFIG_VQ_MVD_CODING
+#if CONFIG_MV_RANGE_EXTENSION
+              { AOM_CDF2(16384) },
+              { AOM_CDF2(16384) },
+#endif        // CONFIG_MV_RANGE_EXTENSION
+          },  // bits_cdf
+#endif        // !CONFIG_VQ_MVD_CODING
       },
   },
 };
diff --git a/av1/common/entropymv.h b/av1/common/entropymv.h
index 2fa1913..6d13cf2 100644
--- a/av1/common/entropymv.h
+++ b/av1/common/entropymv.h
@@ -47,7 +47,6 @@
 }
 
 /* Symbols for coding magnitude class of nonzero components */
-#define MV_CLASSES 11
 enum {
   /* Class specifies the integer pel range */
   MV_CLASS_0 = 0,   /* When AMVD is applied:(0, 1], {2}. Otherwise:(0, 2] */
@@ -60,13 +59,17 @@
   MV_CLASS_7 = 7,   /* When AMVD is applied:{256}. Otherwise:(128, 256] */
   MV_CLASS_8 = 8,   /* When AMVD is applied:{512}. Otherwise:(256, 512] */
   MV_CLASS_9 = 9,   /* When AMVD is applied:{1024}. Otherwise:(512, 1024] */
-  MV_CLASS_10 = 10, /* When AMVD is applied:{2048}. Otherwise:(1024,2048] */
+  MV_CLASS_10 = 10, /* When AMVD is applied:{2048}. Otherwise:(1024, 2048] */
+#if CONFIG_MV_RANGE_EXTENSION
+  MV_CLASS_11 = 11, /* When AMVD is applied:{2048}. Otherwise:(2048, 4096] */
+  MV_CLASS_12 = 12, /* When AMVD is applied:{4096}. Otherwise:(4096, 8192] */
+#endif              // CONFIG_MV_RANGE_EXTENSION
+  MV_CLASSES,       /* Maximum MV class */
 } UENUM1BYTE(MV_CLASS_TYPE);
 
 #define CLASS0_BITS 1 /* bits at integer precision for class 0 */
 #define CLASS0_SIZE (1 << CLASS0_BITS)
 #define MV_OFFSET_BITS (MV_CLASSES + CLASS0_BITS - 2)
-#define MV_BITS_CONTEXTS 6
 #define MV_MAX_BITS (MV_CLASSES + CLASS0_BITS + 2)
 #define MV_MAX ((1 << MV_MAX_BITS) - 1)
 #define MV_VALS ((MV_MAX << 1) + 1)
@@ -111,9 +114,24 @@
   aom_cdf_prob joint_shell_class_cdf_1[NUM_MV_PRECISIONS]
                                       [CDF_SIZE(SECOND_SHELL_CLASS)];
 #else
+#if CONFIG_MV_RANGE_EXTENSION
+  // For MV_PRECISION_ONE_EIGHTH_PEL, class 15 and 16 are coded as a
+  // single class, another flag to distinguish them
+  aom_cdf_prob joint_shell_class_cdf[NUM_MV_PRECISIONS]
+                                    [CDF_SIZE(MAX_NUM_SHELL_CLASS - 1)];
+#else
   aom_cdf_prob joint_shell_class_cdf[NUM_MV_PRECISIONS]
                                     [CDF_SIZE(MAX_NUM_SHELL_CLASS)];
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
+
+#if CONFIG_MV_RANGE_EXTENSION
+  // Only MV_PRECISION_ONE_EIGHTH_PEL has shell class 15 and class 16.
+  // For MV_PRECISION_ONE_EIGHTH_PEL, class 15 and 16 are coded as a
+  // single class, then another flag to distinguish them
+  aom_cdf_prob joint_shell_last_two_classes_cdf[CDF_SIZE(2)];
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
   aom_cdf_prob shell_offset_low_class_cdf[2][CDF_SIZE(2)];
 
 #if CONFIG_MVD_CDF_REDUCTION
diff --git a/av1/common/mv.h b/av1/common/mv.h
index ac35391..fc556f7 100644
--- a/av1/common/mv.h
+++ b/av1/common/mv.h
@@ -23,11 +23,16 @@
 extern "C" {
 #endif
 
-#define INVALID_MV 0x80008000
 #define GET_MV_RAWPEL(x) (((x) + 3 + ((x) >= 0)) >> 3)
 #define GET_MV_SUBPEL(x) ((x) * 8)
 
+#if CONFIG_MV_RANGE_EXTENSION
+#define INVALID_MV 0x2000020000
+#define MV_IN_USE_BITS 16
+#else
+#define INVALID_MV 0x80008000
 #define MV_IN_USE_BITS 14
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #define MV_UPP (1 << MV_IN_USE_BITS)
 #define MV_LOW (-(1 << MV_IN_USE_BITS))
 
@@ -37,23 +42,35 @@
   } while (0);
 #define CHECK_MV_EQUAL(x, y) (((x).row == (y).row) && ((x).col == (y).col))
 
+#if CONFIG_MV_RANGE_EXTENSION
+// Data type of MV component
+#define MV_COMP_DATA_TYPE int32_t
+// Data type of MV
+#define MV_DATA_TYPE uint64_t
+#else
+// Data type of MV component
+#define MV_COMP_DATA_TYPE int16_t
+// Data type of MV
+#define MV_DATA_TYPE uint32_t
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
 // The motion vector in units of full pixel
 typedef struct fullpel_mv {
-  int16_t row;
-  int16_t col;
+  MV_COMP_DATA_TYPE row;
+  MV_COMP_DATA_TYPE col;
 } FULLPEL_MV;
 
 // The motion vector in units of 1/8-pel
 typedef struct mv {
-  int16_t row;
-  int16_t col;
+  MV_COMP_DATA_TYPE row;
+  MV_COMP_DATA_TYPE col;
 } MV;
 
 static const MV kZeroMv = { 0, 0 };
 static const FULLPEL_MV kZeroFullMv = { 0, 0 };
 
 typedef union int_mv {
-  uint32_t as_int;
+  MV_DATA_TYPE as_int;
   MV as_mv;
   FULLPEL_MV as_fullmv;
 } int_mv; /* facilitates faster equality tests and copies */
@@ -116,7 +133,11 @@
   ((NUM_MV_PRECISIONS) - (MV_PRECISION_HALF_PEL))
 
 #if CONFIG_VQ_MVD_CODING
+#if CONFIG_MV_RANGE_EXTENSION
+#define MAX_NUM_SHELL_CLASS 17
+#else
 #define MAX_NUM_SHELL_CLASS 15
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_VQ_MVD_CODING
 // The mv limit for fullpel mvs
 typedef struct {
@@ -135,8 +156,9 @@
 } SubpelMvLimits;
 
 static AOM_INLINE FULLPEL_MV get_fullmv_from_mv(const MV *subpel_mv) {
-  const FULLPEL_MV full_mv = { (int16_t)GET_MV_RAWPEL(subpel_mv->row),
-                               (int16_t)GET_MV_RAWPEL(subpel_mv->col) };
+  const FULLPEL_MV full_mv = { (MV_COMP_DATA_TYPE)GET_MV_RAWPEL(subpel_mv->row),
+                               (MV_COMP_DATA_TYPE)GET_MV_RAWPEL(
+                                   subpel_mv->col) };
   return full_mv;
 }
 
@@ -164,8 +186,8 @@
 #endif  // CONFIG_C071_SUBBLK_WARPMV
 
 static AOM_INLINE MV get_mv_from_fullmv(const FULLPEL_MV *full_mv) {
-  const MV subpel_mv = { (int16_t)GET_MV_SUBPEL(full_mv->row),
-                         (int16_t)GET_MV_SUBPEL(full_mv->col) };
+  const MV subpel_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(full_mv->row),
+                         (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(full_mv->col) };
   return subpel_mv;
 }
 
@@ -677,11 +699,11 @@
 } WARP_CANDIDATE;
 
 static INLINE int is_zero_mv(const MV *mv) {
-  return *((const uint32_t *)mv) == 0;
+  return *((const MV_DATA_TYPE *)mv) == 0;
 }
 
 static INLINE int is_equal_mv(const MV *a, const MV *b) {
-  return *((const uint32_t *)a) == *((const uint32_t *)b);
+  return *((const MV_DATA_TYPE *)a) == *((const MV_DATA_TYPE *)b);
 }
 
 static INLINE void clamp_mv(MV *mv, const SubpelMvLimits *mv_limits) {
@@ -704,6 +726,13 @@
 }
 #endif  // CONFIG_IMPROVE_REFINED_MV
 
+#if CONFIG_MV_RANGE_EXTENSION
+static INLINE int get_map_shell_class(const int shell_class) {
+  return shell_class >= MAX_NUM_SHELL_CLASS - 2 ? MAX_NUM_SHELL_CLASS - 2
+                                                : shell_class;
+}
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index a284ce8..f93efb0 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -3843,9 +3843,9 @@
 #endif  // CONFIG_IBC_BV_IMPROVEMENT && CONFIG_IBC_MAX_DRL
       CANDIDATE_MV tmp_mv;
       tmp_mv.this_mv.as_mv.col =
-          (int16_t)GET_MV_SUBPEL(default_ref_bv_list[i][0]);
+          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(default_ref_bv_list[i][0]);
       tmp_mv.this_mv.as_mv.row =
-          (int16_t)GET_MV_SUBPEL(default_ref_bv_list[i][1]);
+          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(default_ref_bv_list[i][1]);
       tmp_mv.comp_mv.as_int = 0;
       add_to_ref_bv_list(tmp_mv, ref_mv_stack, ref_mv_weight, refmv_count);
     }
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index 05493f0..9f1be55 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -661,8 +661,8 @@
   const int mv_col = (int)ROUND_POWER_OF_TWO_SIGNED_64(scale_mv_col, 14);
   const int clamp_max = MV_UPP - 1;
   const int clamp_min = MV_LOW + 1;
-  output->row = (int16_t)clamp(mv_row, clamp_min, clamp_max);
-  output->col = (int16_t)clamp(mv_col, clamp_min, clamp_max);
+  output->row = (MV_COMP_DATA_TYPE)clamp(mv_row, clamp_min, clamp_max);
+  output->col = (MV_COMP_DATA_TYPE)clamp(mv_col, clamp_min, clamp_max);
 }
 
 void av1_setup_frame_buf_refs(AV1_COMMON *cm);
@@ -1436,8 +1436,8 @@
   const int mv_col = (int)ROUND_POWER_OF_TWO_SIGNED_64(scale_mv_col, 14);
   const int clamp_max = MV_UPP - 1;
   const int clamp_min = MV_LOW + 1;
-  output->row = (int16_t)clamp(mv_row, clamp_min, clamp_max);
-  output->col = (int16_t)clamp(mv_col, clamp_min, clamp_max);
+  output->row = (MV_COMP_DATA_TYPE)clamp(mv_row, clamp_min, clamp_max);
+  output->col = (MV_COMP_DATA_TYPE)clamp(mv_col, clamp_min, clamp_max);
 }
 
 // Compute TMVP unit offset related to block mv
@@ -1505,14 +1505,14 @@
     tip_mv[0].as_int = 0;
     tip_mv[1].as_int = 0;
   }
-  tip_mv[0].as_mv.row = (int16_t)clamp(tip_mv[0].as_mv.row + block_mv->row,
-                                       MV_LOW + 1, MV_UPP - 1);
-  tip_mv[0].as_mv.col = (int16_t)clamp(tip_mv[0].as_mv.col + block_mv->col,
-                                       MV_LOW + 1, MV_UPP - 1);
-  tip_mv[1].as_mv.row = (int16_t)clamp(tip_mv[1].as_mv.row + block_mv->row,
-                                       MV_LOW + 1, MV_UPP - 1);
-  tip_mv[1].as_mv.col = (int16_t)clamp(tip_mv[1].as_mv.col + block_mv->col,
-                                       MV_LOW + 1, MV_UPP - 1);
+  tip_mv[0].as_mv.row = (MV_COMP_DATA_TYPE)clamp(
+      tip_mv[0].as_mv.row + block_mv->row, MV_LOW + 1, MV_UPP - 1);
+  tip_mv[0].as_mv.col = (MV_COMP_DATA_TYPE)clamp(
+      tip_mv[0].as_mv.col + block_mv->col, MV_LOW + 1, MV_UPP - 1);
+  tip_mv[1].as_mv.row = (MV_COMP_DATA_TYPE)clamp(
+      tip_mv[1].as_mv.row + block_mv->row, MV_LOW + 1, MV_UPP - 1);
+  tip_mv[1].as_mv.col = (MV_COMP_DATA_TYPE)clamp(
+      tip_mv[1].as_mv.col + block_mv->col, MV_LOW + 1, MV_UPP - 1);
 }
 
 #ifdef __cplusplus
diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h
index 8af43f0..1c925b1 100644
--- a/av1/common/reconinter.h
+++ b/av1/common/reconinter.h
@@ -1339,13 +1339,13 @@
   if (use_optflow_refinement) {
     // optflow refinement always returns MVs with 1/16 precision so it is not
     // necessary to shift the MV before clamping
-    clamped_mv.row = (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+    clamped_mv.row = (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED(
         src_mv->row * (1 << SUBPEL_BITS), MV_REFINE_PREC_BITS + ss_y);
-    clamped_mv.col = (int16_t)ROUND_POWER_OF_TWO_SIGNED(
+    clamped_mv.col = (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED(
         src_mv->col * (1 << SUBPEL_BITS), MV_REFINE_PREC_BITS + ss_x);
   } else {
-    clamped_mv.row = (int16_t)(src_mv->row * (1 << (1 - ss_y)));
-    clamped_mv.col = (int16_t)(src_mv->col * (1 << (1 - ss_x)));
+    clamped_mv.row = (MV_COMP_DATA_TYPE)(src_mv->row * (1 << (1 - ss_y)));
+    clamped_mv.col = (MV_COMP_DATA_TYPE)(src_mv->col * (1 << (1 - ss_x)));
   }
   assert(ss_x <= 1);
   assert(ss_y <= 1);
diff --git a/av1/common/tip.c b/av1/common/tip.c
index 272d4a8..3730d75 100644
--- a/av1/common/tip.c
+++ b/av1/common/tip.c
@@ -521,11 +521,11 @@
           if (weights) {
             const int scale_factor = weight_div_mult[weights];
             tpl_mfs[blk_pos_in_sb].as_mv.row =
-                (int16_t)ROUND_POWER_OF_TWO_SIGNED(sum_mv_row * scale_factor,
-                                                   DIV_SHIFT_BITS);
+                (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED(
+                    sum_mv_row * scale_factor, DIV_SHIFT_BITS);
             tpl_mfs[blk_pos_in_sb].as_mv.col =
-                (int16_t)ROUND_POWER_OF_TWO_SIGNED(sum_mv_col * scale_factor,
-                                                   DIV_SHIFT_BITS);
+                (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED(
+                    sum_mv_col * scale_factor, DIV_SHIFT_BITS);
           } else {
             tpl_mfs[blk_pos_in_sb].as_int = INVALID_MV;
           }
@@ -558,8 +558,8 @@
   const int spel_right = spel_left - SUBPEL_SHIFTS;
   const int spel_top = (AOM_INTERP_EXTEND + bh) << SUBPEL_BITS;
   const int spel_bottom = spel_top - SUBPEL_SHIFTS;
-  MV clamped_mv = { (int16_t)(src_mv->row * (1 << (1 - ss_y))),
-                    (int16_t)(src_mv->col * (1 << (1 - ss_x))) };
+  MV clamped_mv = { (MV_COMP_DATA_TYPE)(src_mv->row * (1 << (1 - ss_y))),
+                    (MV_COMP_DATA_TYPE)(src_mv->col * (1 << (1 - ss_x))) };
   assert(ss_x <= 1);
   assert(ss_y <= 1);
   const SubpelMvLimits mv_limits = {
@@ -1544,14 +1544,18 @@
                               tip_ref->ref_frames_offset_sf[0]);
         tip_get_mv_projection(&mv[1], tpl_mvs->mfmv0.as_mv,
                               tip_ref->ref_frames_offset_sf[1]);
-        mv[0].row = (int16_t)clamp(mv[0].row + cm->tip_global_motion.as_mv.row,
-                                   MV_LOW + 1, MV_UPP - 1);
-        mv[0].col = (int16_t)clamp(mv[0].col + cm->tip_global_motion.as_mv.col,
-                                   MV_LOW + 1, MV_UPP - 1);
-        mv[1].row = (int16_t)clamp(mv[1].row + cm->tip_global_motion.as_mv.row,
-                                   MV_LOW + 1, MV_UPP - 1);
-        mv[1].col = (int16_t)clamp(mv[1].col + cm->tip_global_motion.as_mv.col,
-                                   MV_LOW + 1, MV_UPP - 1);
+        mv[0].row = (MV_COMP_DATA_TYPE)clamp(
+            mv[0].row + cm->tip_global_motion.as_mv.row, MV_LOW + 1,
+            MV_UPP - 1);
+        mv[0].col = (MV_COMP_DATA_TYPE)clamp(
+            mv[0].col + cm->tip_global_motion.as_mv.col, MV_LOW + 1,
+            MV_UPP - 1);
+        mv[1].row = (MV_COMP_DATA_TYPE)clamp(
+            mv[1].row + cm->tip_global_motion.as_mv.row, MV_LOW + 1,
+            MV_UPP - 1);
+        mv[1].col = (MV_COMP_DATA_TYPE)clamp(
+            mv[1].col + cm->tip_global_motion.as_mv.col, MV_LOW + 1,
+            MV_UPP - 1);
       } else {
         mv[0] = cm->tip_global_motion.as_mv;
         mv[1] = cm->tip_global_motion.as_mv;
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index f32f0f5..2887e9d 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -2644,7 +2644,6 @@
 #if CONFIG_MVD_CDF_REDUCTION
         bit_idx ? aom_read_literal(r, 1, ACCT_INFO("greater_flags")) :
 #endif  // CONFIG_MVD_CDF_REDUCTION
-
                 aom_read_symbol(
                     r, cdf, 2,
                     ACCT_INFO("greater_flags", "col_mv_greater_flags_cdf"));
@@ -2762,25 +2761,63 @@
   shell_set = aom_read_symbol(r, ctx->joint_shell_set_cdf, 2,
                               ACCT_INFO("shell_set", "joint_shell_set_cdf"));
   if (shell_set) {
+#if CONFIG_MV_RANGE_EXTENSION
+    if (precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      shell_class =
+          num_mv_class_0 +
+          aom_read_symbol(
+              r, ctx->joint_shell_class_cdf_1[precision], num_mv_class_1 - 1,
+              ACCT_INFO("shell_class_1", "joint_shell_class_cdf_1"));
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        shell_class += aom_read_symbol(
+            r, ctx->joint_shell_last_two_classes_cdf, 2,
+            ACCT_INFO("shell_class", "joint_shell_last_two_classes_cdf"));
+      }
+    } else {
+      shell_class =
+          num_mv_class_0 +
+          aom_read_symbol(
+              r, ctx->joint_shell_class_cdf_1[precision], num_mv_class_1,
+              ACCT_INFO("shell_class_1", "joint_shell_class_cdf_1"));
+    }
+#else
     shell_class =
         num_mv_class_0 +
         aom_read_symbol(r, ctx->joint_shell_class_cdf_1[precision],
                         num_mv_class_1,
                         ACCT_INFO("shell_class_1", "joint_shell_class_cdf_1"));
+#endif  // CONFIG_MV_RANGE_EXTENSION
   } else {
     shell_class = aom_read_symbol(
         r, ctx->joint_shell_class_cdf_0[precision], num_mv_class_0,
         ACCT_INFO("shell_class_0", "joint_shell_class_cdf_0"));
   }
 #else
+#if CONFIG_MV_RANGE_EXTENSION
+  int shell_class = 0;
+  if (precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+    shell_class = aom_read_symbol(
+        r, ctx->joint_shell_class_cdf[precision], num_mv_class - 1,
+        ACCT_INFO("shell_class", "joint_shell_class_cdf"));
+    if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+      shell_class += aom_read_symbol(
+          r, ctx->joint_shell_last_two_classes_cdf, 2,
+          ACCT_INFO("shell_class", "joint_shell_last_two_classes_cdf"));
+    }
+  } else {
+    shell_class =
+        aom_read_symbol(r, ctx->joint_shell_class_cdf[precision], num_mv_class,
+                        ACCT_INFO("shell_class", "joint_shell_class_cdf"));
+  }
+#else
   const int shell_class =
       aom_read_symbol(r, ctx->joint_shell_class_cdf[precision], num_mv_class,
                       ACCT_INFO("shell_class", "joint_shell_class_cdf"));
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   assert(shell_class < num_mv_class);
 
   // Decode shell class offset
-
   int shell_cls_offset = 0;
 
   if (shell_class < 2) {
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index ab454c8..1eff202 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -1423,7 +1423,7 @@
   /*! costs to code mvd shell index. */
   int nmv_joint_shell_cost[NUM_MV_PRECISIONS][(2 * MV_MAX) + 1];
 
-  /*! costs to code col_mv_greter_flags. */
+  /*! costs to code col_mv_greater_flags. */
   int col_mv_greater_flags_costs[NUM_MV_PRECISIONS]
                                 [MAX_COL_TRUNCATED_UNARY_VAL + 1]
                                 [MAX_COL_TRUNCATED_UNARY_VAL + 1];
diff --git a/av1/encoder/encodeframe_utils.c b/av1/encoder/encodeframe_utils.c
index 3572df9..93cd438 100644
--- a/av1/encoder/encodeframe_utils.c
+++ b/av1/encoder/encodeframe_utils.c
@@ -1345,16 +1345,38 @@
     split_num_shell_class(num_mv_class, &num_mv_class_0, &num_mv_class_1);
     AVERAGE_CDF(nmv_left->joint_shell_class_cdf_0[prec],
                 nmv_tr->joint_shell_class_cdf_0[prec], num_mv_class_0);
-    AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
-                nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                  nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1 - 1);
+      AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                  nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf_1[prec],
+                  nmv_tr->joint_shell_class_cdf_1[prec], num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
   for (int prec = 0; prec < NUM_MV_PRECISIONS; prec++) {
     int num_mv_class = get_default_num_shell_class(prec);
-    AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
-                nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (prec == MV_PRECISION_ONE_EIGHTH_PEL) {
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                  nmv_tr->joint_shell_class_cdf[prec], num_mv_class - 1);
+      AVERAGE_CDF(nmv_left->joint_shell_last_two_classes_cdf,
+                  nmv_tr->joint_shell_last_two_classes_cdf, 2);
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      AVERAGE_CDF(nmv_left->joint_shell_class_cdf[prec],
+                  nmv_tr->joint_shell_class_cdf[prec], num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
-#endif
+#endif  // CONFIG_REDUCE_SYMBOL_SIZE
   AVERAGE_CDF(nmv_left->shell_offset_low_class_cdf,
               nmv_tr->shell_offset_low_class_cdf, 2);
   AVERAGE_CDF(nmv_left->shell_offset_class2_cdf,
diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c
index 22e6b7b..309c765 100644
--- a/av1/encoder/encodemv.c
+++ b/av1/encoder/encodemv.c
@@ -365,14 +365,44 @@
                      num_mv_class_0);
   } else {
     aom_write_symbol(w, 1, mvctx->joint_shell_set_cdf, 2);
-    aom_write_symbol(w, shell_class - num_mv_class_0,
-                     mvctx->joint_shell_class_cdf_1[pb_mv_precision],
-                     num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      const int map_shell_class = get_map_shell_class(shell_class);
+      aom_write_symbol(w, map_shell_class - num_mv_class_0,
+                       mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                       num_mv_class_1 - 1);
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        aom_write_symbol(w, shell_class == MAX_NUM_SHELL_CLASS - 1,
+                         mvctx->joint_shell_last_two_classes_cdf, 2);
+      }
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      aom_write_symbol(w, shell_class - num_mv_class_0,
+                       mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                       num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
-    aom_write_symbol(w, shell_class,
-                     mvctx->joint_shell_class_cdf[pb_mv_precision],
-                     num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      const int map_shell_class = get_map_shell_class(shell_class);
+      aom_write_symbol(w, map_shell_class,
+                       mvctx->joint_shell_class_cdf[pb_mv_precision],
+                       num_mv_class - 1);
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        aom_write_symbol(w, shell_class == MAX_NUM_SHELL_CLASS - 1,
+                         mvctx->joint_shell_last_two_classes_cdf, 2);
+      }
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      aom_write_symbol(w, shell_class,
+                       mvctx->joint_shell_class_cdf[pb_mv_precision],
+                       num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
 
   assert(shell_class >= 0 && shell_class < num_mv_class);
@@ -474,12 +504,41 @@
                num_mv_class_0);
   } else {
     update_cdf(mvctx->joint_shell_set_cdf, 1, 2);
-    update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
-               shell_class - num_mv_class_0, num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      const int map_shell_class = get_map_shell_class(shell_class);
+      update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                 map_shell_class - num_mv_class_0, num_mv_class_1 - 1);
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        update_cdf(mvctx->joint_shell_last_two_classes_cdf,
+                   shell_class == MAX_NUM_SHELL_CLASS - 1, 2);
+      }
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                 shell_class - num_mv_class_0, num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
-    update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], shell_class,
-               num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      const int map_shell_class = get_map_shell_class(shell_class);
+      update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], map_shell_class,
+                 num_mv_class - 1);
+
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        update_cdf(mvctx->joint_shell_last_two_classes_cdf,
+                   shell_class == MAX_NUM_SHELL_CLASS - 1, 2);
+      }
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], shell_class,
+                 num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
   assert(shell_class >= 0 && shell_class < num_mv_class);
 
@@ -1032,8 +1091,17 @@
   int joint_shell_class_cost_0[FIRST_SHELL_CLASS];
   int joint_shell_class_cost_1[SECOND_SHELL_CLASS];
 #else
+#if CONFIG_MV_RANGE_EXTENSION
+    int joint_shell_class_cost[MAX_NUM_SHELL_CLASS - 1];
+#else
     int joint_shell_class_cost[MAX_NUM_SHELL_CLASS];
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
+
+#if CONFIG_MV_RANGE_EXTENSION
+  int joint_shell_last_two_classes_cost[2];
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
   int shell_offset_low_class_cost[2][2];
 
 #if CONFIG_MVD_CDF_REDUCTION
@@ -1070,6 +1138,13 @@
                              ctx->joint_shell_class_cdf[precision], NULL);
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
 
+#if CONFIG_MV_RANGE_EXTENSION
+  if (precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+    av1_cost_tokens_from_cdf(joint_shell_last_two_classes_cost,
+                             ctx->joint_shell_last_two_classes_cdf, NULL);
+  }
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
   for (int i = 0; i < 2; i++) {
     av1_cost_tokens_from_cdf(shell_offset_low_class_cost[i],
                              ctx->shell_offset_low_class_cdf[i], NULL);
@@ -1193,11 +1268,40 @@
       shell_cost[shell_index] += joint_shell_class_cost_0[shell_class];
     } else {
       shell_cost[shell_index] += joint_shell_set_cost[1];
-      shell_cost[shell_index] +=
-          joint_shell_class_cost_1[shell_class - num_mv_class_0];
+#if CONFIG_MV_RANGE_EXTENSION
+      if (precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+        const int map_shell_class = get_map_shell_class(shell_class);
+        shell_cost[shell_index] +=
+            joint_shell_class_cost_1[map_shell_class - num_mv_class_0];
+        if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+          const int is_last_class = (shell_class == MAX_NUM_SHELL_CLASS - 1);
+          shell_cost[shell_index] +=
+              joint_shell_last_two_classes_cost[is_last_class];
+        }
+      } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+        shell_cost[shell_index] +=
+            joint_shell_class_cost_1[shell_class - num_mv_class_0];
+#if CONFIG_MV_RANGE_EXTENSION
+      }
+#endif  // CONFIG_MV_RANGE_EXTENSION
     }
 #else
-      shell_cost[shell_index] += joint_shell_class_cost[shell_class];
+#if CONFIG_MV_RANGE_EXTENSION
+      if (precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+        const int map_shell_class = get_map_shell_class(shell_class);
+        shell_cost[shell_index] += joint_shell_class_cost[map_shell_class];
+        if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+          const int is_last_class = (shell_class == MAX_NUM_SHELL_CLASS - 1);
+          shell_cost[shell_index] +=
+              joint_shell_last_two_classes_cost[is_last_class];
+        }
+      } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+        shell_cost[shell_index] += joint_shell_class_cost[shell_class];
+#if CONFIG_MV_RANGE_EXTENSION
+      }
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
     assert(shell_class >= 0 && shell_class < num_mv_class);
 
diff --git a/av1/encoder/encodemv.h b/av1/encoder/encodemv.h
index e6f054a..6fb2381 100644
--- a/av1/encoder/encodemv.h
+++ b/av1/encoder/encodemv.h
@@ -117,7 +117,7 @@
 static INLINE MV_CLASS_TYPE av1_get_mv_class(int z, int *offset) {
   assert(z >= 0);
   const MV_CLASS_TYPE c = (MV_CLASS_TYPE)av1_log_in_base_2(z >> 3);
-  assert(c <= MV_CLASS_10);
+  assert(c < MV_CLASSES);
   if (offset) *offset = z - av1_mv_class_base(c);
   return c;
 }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index a209260..b503f83 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1790,7 +1790,13 @@
   const int max_mv_def = AOMMAX(cm->width, cm->height);
 
   // Default based on max resolution.
-  mv_search_params->mv_step_param = av1_init_search_range(max_mv_def);
+  mv_search_params->mv_step_param =
+      av1_init_search_range(max_mv_def
+#if CONFIG_MV_RANGE_EXTENSION
+                            ,
+                            cpi->oxcf.tool_cfg.enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      );
 
   if (cpi->sf.mv_sf.auto_mv_step_size) {
     if (frame_is_intra_only(cm)) {
@@ -1804,7 +1810,12 @@
         // in the previous frame, capped by the default max_mv_magnitude based
         // on resolution.
         mv_search_params->mv_step_param = av1_init_search_range(
-            AOMMIN(max_mv_def, 2 * mv_search_params->max_mv_magnitude));
+            AOMMIN(max_mv_def, 2 * mv_search_params->max_mv_magnitude)
+#if CONFIG_MV_RANGE_EXTENSION
+                ,
+            cpi->oxcf.tool_cfg.enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+        );
       }
       mv_search_params->max_mv_magnitude = -1;
     }
@@ -2125,6 +2136,9 @@
 // Function pointer to search site config initialization
 // of different search method functions.
 typedef void (*av1_init_search_site_config)(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                            int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
                                             int stride);
 
 av1_init_search_site_config
@@ -2164,13 +2178,24 @@
   // Initialization of search_site_cfg for NUM_DISTINCT_SEARCH_METHODS.
   for (SEARCH_METHODS i = DIAMOND; i < NUM_DISTINCT_SEARCH_METHODS; i++) {
     av1_init_motion_compensation[i](
-        &mv_search_params->search_site_cfg[SS_CFG_SRC][i], y_stride);
+        &mv_search_params->search_site_cfg[SS_CFG_SRC][i],
+#if CONFIG_MV_RANGE_EXTENSION
+        cpi->oxcf.tool_cfg.enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+        y_stride);
     av1_init_motion_compensation[i](
-        &mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][i], y_stride_src);
+        &mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][i],
+#if CONFIG_MV_RANGE_EXTENSION
+        cpi->oxcf.tool_cfg.enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+        y_stride_src);
   }
 
   // First pass search site config initialization.
   av1_init_motion_fpf(&mv_search_params->search_site_cfg[SS_CFG_FPF][DIAMOND],
+#if CONFIG_MV_RANGE_EXTENSION
+                      cpi->oxcf.tool_cfg.enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
                       fpf_y_stride);
   for (SEARCH_METHODS i = NSTEP; i < NUM_DISTINCT_SEARCH_METHODS; i++) {
     memcpy(&mv_search_params->search_site_cfg[SS_CFG_FPF][i],
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 2d48678..115de67 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -905,6 +905,10 @@
   // enable MV trajectory tracking
   int enable_mv_traj;
 #endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+  // enable a large motion search window
+  int enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   // enable block adaptive weighted prediction
   int enable_bawp;
   // enable compound weighted prediction
@@ -1307,16 +1311,24 @@
   unsigned int joint_shell_class_1_cnts[NUM_MV_PRECISIONS]
                                        [CDF_SIZE(SECOND_SHELL_CLASS)];
 #else
+#if CONFIG_MV_RANGE_EXTENSION
+  unsigned int joint_shell_class_cnts[NUM_MV_PRECISIONS][CDF_SIZE(
+      MAX_NUM_SHELL_CLASS - 1)];  // placeholder
+#else
   unsigned int joint_shell_class_cnts[NUM_MV_PRECISIONS][CDF_SIZE(
       MAX_NUM_SHELL_CLASS)];  // placeholder
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
+#if CONFIG_MV_RANGE_EXTENSION
+  unsigned int joint_shell_last_two_classes_cnts[CDF_SIZE(2)];  // placeholder
+#endif  // CONFIG_MV_RANGE_EXTENSION
   unsigned int shell_offset_low_class_cnts[2][CDF_SIZE(2)];  // placeholder
   unsigned int shell_offset_class2_cnts[3][CDF_SIZE(2)];     // // placeholder
   unsigned int shell_offset_other_class_cnts[NUM_CTX_CLASS_OFFSETS]
                                             [SHELL_INT_OFFSET_BIT]
                                             [CDF_SIZE(2)];  // placeholder
-  unsigned int col_mv_greter_flags_cnts[NUM_CTX_COL_MV_GTX]
-                                       [CDF_SIZE(2)];  // placeholder
+  unsigned int col_mv_greater_flags_cnts[NUM_CTX_COL_MV_GTX]
+                                        [CDF_SIZE(2)];  // placeholder
   unsigned int col_mv_index_cnts[NUM_CTX_COL_MV_INDEX]
                                 [CDF_SIZE(2)];  // placeholder
 #else
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index e841958..42cb00a 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -185,11 +185,22 @@
 
 // Refine the motion search range according to the frame dimension
 // for first pass test.
-static int get_search_range(const InitialDimensions *initial_dimensions) {
+static int get_search_range(const InitialDimensions *initial_dimensions
+#if CONFIG_MV_RANGE_EXTENSION
+                            ,
+                            int enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+) {
   int sr = 0;
   const int dim = AOMMIN(initial_dimensions->width, initial_dimensions->height);
 
-  while ((dim << sr) < MAX_FULL_PEL_VAL) ++sr;
+#if CONFIG_MV_RANGE_EXTENSION
+  const int max_full_range =
+      enable_high_motion ? MAX_FULL_PEL_VAL : LOW_MOTION_MAX_FULL_PEL_VAL;
+#else
+  const int max_full_range = MAX_FULL_PEL_VAL;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  while ((dim << sr) < max_full_range) ++sr;
   return sr;
 }
 
@@ -203,7 +214,12 @@
   int tmp_err;
   const BLOCK_SIZE bsize = xd->mi[0]->sb_type[xd->tree_type == CHROMA_PART];
   const int new_mv_mode_penalty = NEW_MV_MODE_PENALTY;
-  const int sr = get_search_range(&cpi->initial_dimensions);
+  const int sr = get_search_range(&cpi->initial_dimensions
+#if CONFIG_MV_RANGE_EXTENSION
+                                  ,
+                                  cpi->oxcf.tool_cfg.enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  );
   const int step_param = 3 + sr;
 
   const search_site_config *first_pass_search_sites =
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index d5b3716..a3cbe81 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -446,14 +446,28 @@
 }
 #endif  // !CONFIG_TIP_MV_SIMPLIFICATION
 
-int av1_init_search_range(int size) {
+int av1_init_search_range(int size
+#if CONFIG_MV_RANGE_EXTENSION
+                          ,
+                          int enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+) {
   int sr = 0;
   // Minimum search size no matter what the passed in value.
   size = AOMMAX(16, size);
 
-  while ((size << sr) < MAX_FULL_PEL_VAL) sr++;
+#if CONFIG_MV_RANGE_EXTENSION
+  const int max_full_range =
+      enable_high_motion ? MAX_FULL_PEL_VAL : LOW_MOTION_MAX_FULL_PEL_VAL;
+  const int max_search_steps =
+      enable_high_motion ? MAX_MVSEARCH_STEPS - 2 : MAX_MVSEARCH_STEPS - 4;
+#else
+  const int max_full_range = MAX_FULL_PEL_VAL;
+  const int max_search_steps = MAX_MVSEARCH_STEPS - 2;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  while ((size << sr) < max_full_range) sr++;
 
-  sr = AOMMIN(sr, MAX_MVSEARCH_STEPS - 2);
+  sr = AOMMIN(sr, max_search_steps);
   return sr;
 }
 
@@ -957,19 +971,36 @@
 // =============================================================================
 //  Fullpixel Motion Search: Translational
 // =============================================================================
+#if CONFIG_MV_RANGE_EXTENSION
+#define MAX_PATTERN_SCALES 13
+#else
 #define MAX_PATTERN_SCALES 11
+#endif                            // CONFIG_MV_RANGE_EXTENSION
 #define MAX_PATTERN_CANDIDATES 8  // max number of candidates per scale
 #define PATTERN_CANDIDATES_REF 3  // number of refinement candidates
 
-void av1_init_dsmotion_compensation(search_site_config *cfg, int stride) {
+void av1_init_dsmotion_compensation(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                    int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                    int stride) {
   int num_search_steps = 0;
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  int stage_index =
+      enable_high_motion ? MAX_MVSEARCH_STEPS - 1 : MAX_MVSEARCH_STEPS - 3;
+  const int init_radius =
+      enable_high_motion ? MAX_FIRST_STEP : LOW_MOTION_MAX_FIRST_STEP;
+#else
   int stage_index = MAX_MVSEARCH_STEPS - 1;
+  const int init_radius = MAX_FIRST_STEP;
+#endif  // CONFIG_MV_RANGE_EXTENSION
 
   cfg->site[stage_index][0].mv.col = cfg->site[stage_index][0].mv.row = 0;
   cfg->site[stage_index][0].offset = 0;
   cfg->stride = stride;
 
-  for (int radius = MAX_FIRST_STEP; radius > 0; radius /= 2) {
+  for (int radius = init_radius; radius > 0; radius /= 2) {
     int num_search_pts = 8;
 
     const FULLPEL_MV search_site_mvs[13] = {
@@ -992,15 +1023,28 @@
   cfg->num_search_steps = num_search_steps;
 }
 
-void av1_init_motion_fpf(search_site_config *cfg, int stride) {
+void av1_init_motion_fpf(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                         int stride) {
   int num_search_steps = 0;
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  int stage_index =
+      enable_high_motion ? MAX_MVSEARCH_STEPS - 1 : MAX_MVSEARCH_STEPS - 3;
+  const int init_radius =
+      enable_high_motion ? MAX_FIRST_STEP : LOW_MOTION_MAX_FIRST_STEP;
+#else
   int stage_index = MAX_MVSEARCH_STEPS - 1;
+  const int init_radius = MAX_FIRST_STEP;
+#endif  // CONFIG_MV_RANGE_EXTENSION
 
   cfg->site[stage_index][0].mv.col = cfg->site[stage_index][0].mv.row = 0;
   cfg->site[stage_index][0].offset = 0;
   cfg->stride = stride;
 
-  for (int radius = MAX_FIRST_STEP; radius > 0; radius /= 2) {
+  for (int radius = init_radius; radius > 0; radius /= 2) {
     // Generate offsets for 8 search sites per step.
     int tan_radius = AOMMAX((int)(0.41 * radius), 1);
     int num_search_pts = 12;
@@ -1037,16 +1081,28 @@
 }
 
 // Search site initialization for NSTEP search method.
-void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_nstep(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                        int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                        int stride) {
   int num_search_steps = 0;
   int stage_index = 0;
   cfg->stride = stride;
   int radius = 1;
-#if CONFIG_MV_SEARCH_RANGE
-  for (stage_index = 0; stage_index < 16; ++stage_index) {
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  // 20 corresponds to 17bits mv range for NSTEP
+  const int max_stage_index = enable_high_motion ? 20 : 16;
 #else
-  for (stage_index = 0; stage_index < 15; ++stage_index) {
+#if CONFIG_MV_SEARCH_RANGE
+  const int max_stage_index = 16;
+#else
+  const int max_stage_index = 15;
 #endif  // CONFIG_MV_SEARCH_RANGE
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
+  for (stage_index = 0; stage_index < max_stage_index; ++stage_index) {
     int tan_radius = AOMMAX((int)(0.41 * radius), 1);
     int num_search_pts = 12;
     if (radius <= 5) {
@@ -1087,12 +1143,19 @@
 
 // Search site initialization for BIGDIA / FAST_BIGDIA / FAST_DIAMOND
 // search methods.
-void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_bigdia(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                         int stride) {
   cfg->stride = stride;
   // First scale has 4-closest points, the rest have 8 points in diamond
   // shape at increasing scales
   static const int bigdia_num_candidates[MAX_PATTERN_SCALES] = {
     4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+#if CONFIG_MV_RANGE_EXTENSION
+    8, 8,
+#endif  // CONFIG_MV_RANGE_EXTENSION
   };
 
   // BIGDIA search method candidates.
@@ -1122,11 +1185,24 @@
             { 256, 256 }, { 0, 512 }, { -256, 256 }, { -512, 0 } },
           { { -512, -512 }, { 0, -1024 }, { 512, -512 }, { 1024, 0 },
             { 512, 512 }, { 0, 1024 }, { -512, 512 }, { -1024, 0 } },
+#if CONFIG_MV_RANGE_EXTENSION
+        { { -1024, -1024 }, { 0, -2048 }, { 1024, -1024 }, { 2048, 0 },
+          { 1024, 1024 }, { 0, 2048 }, { -1024, 1024 }, { -2048, 0 } },
+        { { -2048, -2048 }, { 0, -4096 }, { 2048, -2048 }, { 4096, 0 },
+          { 2048, 2048 }, { 0, 4096 }, { -2048, 2048 }, { -4096, 0 } },
+#endif  // CONFIG_MV_RANGE_EXTENSION
         };
 
   /* clang-format on */
   int radius = 1;
-  for (int i = 0; i < MAX_PATTERN_SCALES; ++i) {
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  const int max_search_steps =
+      enable_high_motion ? MAX_PATTERN_SCALES : MAX_PATTERN_SCALES - 2;
+#else
+  const int max_search_steps = MAX_PATTERN_SCALES;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  for (int i = 0; i < max_search_steps; ++i) {
     cfg->searches_per_step[i] = bigdia_num_candidates[i];
     cfg->radius[i] = radius;
     for (int j = 0; j < MAX_PATTERN_CANDIDATES; ++j) {
@@ -1136,15 +1212,22 @@
     }
     radius *= 2;
   }
-  cfg->num_search_steps = MAX_PATTERN_SCALES;
+  cfg->num_search_steps = max_search_steps;
 }
 
 // Search site initialization for SQUARE search method.
-void av1_init_motion_compensation_square(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_square(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                         int stride) {
   cfg->stride = stride;
   // All scales have 8 closest points in square shape.
   static const int square_num_candidates[MAX_PATTERN_SCALES] = {
     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+#if CONFIG_MV_RANGE_EXTENSION
+    8, 8,
+#endif  // CONFIG_MV_RANGE_EXTENSION
   };
 
   // Square search method candidates.
@@ -1174,11 +1257,24 @@
                { 512, 512 }, { 0, 512 }, { -512, 512 }, { -512, 0 } },
              { { -1024, -1024 }, { 0, -1024 }, { 1024, -1024 }, { 1024, 0 },
                { 1024, 1024 }, { 0, 1024 }, { -1024, 1024 }, { -1024, 0 } },
+#if CONFIG_MV_RANGE_EXTENSION
+          { { -2048, -2048 }, { 0, -2048 }, { 2048, -2048 }, { 2048, 0 },
+            { 2048, 2048 }, { 0, 2048 }, { -2048, 2048 }, { -2048, 0 } },
+          { { -4096, -4096 }, { 0, -4096 }, { 4096, -4096 }, { 4096, 0 },
+            { 4096, 4096 }, { 0, 4096 }, { -4096, 4096 }, { -4096, 0 } },
+#endif  // CONFIG_MV_RANGE_EXTENSION
     };
 
   /* clang-format on */
   int radius = 1;
-  for (int i = 0; i < MAX_PATTERN_SCALES; ++i) {
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  const int max_search_steps =
+      enable_high_motion ? MAX_PATTERN_SCALES : MAX_PATTERN_SCALES - 2;
+#else
+  const int max_search_steps = MAX_PATTERN_SCALES;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  for (int i = 0; i < max_search_steps; ++i) {
     cfg->searches_per_step[i] = square_num_candidates[i];
     cfg->radius[i] = radius;
     for (int j = 0; j < MAX_PATTERN_CANDIDATES; ++j) {
@@ -1188,16 +1284,24 @@
     }
     radius *= 2;
   }
-  cfg->num_search_steps = MAX_PATTERN_SCALES;
+  cfg->num_search_steps = max_search_steps;
 }
 
 // Search site initialization for HEX / FAST_HEX search methods.
-void av1_init_motion_compensation_hex(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_hex(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                      int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                      int stride) {
   cfg->stride = stride;
   // First scale has 8-closest points, the rest have 6 points in hex shape
   // at increasing scales.
-  static const int hex_num_candidates[MAX_PATTERN_SCALES] = { 8, 6, 6, 6, 6, 6,
-                                                              6, 6, 6, 6, 6 };
+  static const int hex_num_candidates[MAX_PATTERN_SCALES] = {
+    8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+#if CONFIG_MV_RANGE_EXTENSION
+    6, 6,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  };
   // Note that the largest candidate step at each scale is 2^scale.
   /* clang-format off */
     static const FULLPEL_MV
@@ -1221,11 +1325,24 @@
           { -256, 512 }, { -512, 0 } },
         { { -512, -1024 }, { 512, -1024 }, { 1024, 0 }, { 512, 1024 },
           { -512, 1024 }, { -1024, 0 } },
+#if CONFIG_MV_RANGE_EXTENSION
+          { { -1024, -2048 }, { 1024, -2048 }, { 2048, 0 }, { 1024, 2048 },
+            { -1024, 2048 }, { -2048, 0 } },
+          { { -2048, -4096 }, { 2048, -4096 }, { 4096, 0 }, { 2048, 4096 },
+            { -2048, 4096 }, { -4096, 0 } },
+#endif  // CONFIG_MV_RANGE_EXTENSION
     };
 
   /* clang-format on */
   int radius = 1;
-  for (int i = 0; i < MAX_PATTERN_SCALES; ++i) {
+#if CONFIG_MV_RANGE_EXTENSION
+  cfg->enable_high_motion = enable_high_motion;
+  const int max_search_steps =
+      enable_high_motion ? MAX_PATTERN_SCALES : MAX_PATTERN_SCALES - 2;
+#else
+  const int max_search_steps = MAX_PATTERN_SCALES;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  for (int i = 0; i < max_search_steps; ++i) {
     cfg->searches_per_step[i] = hex_num_candidates[i];
     cfg->radius[i] = radius;
     for (int j = 0; j < hex_num_candidates[i]; ++j) {
@@ -1235,7 +1352,7 @@
     }
     radius *= 2;
   }
-  cfg->num_search_steps = MAX_PATTERN_SCALES;
+  cfg->num_search_steps = max_search_steps;
 }
 
 // Checks whether the mv is within range of the mv_limits
@@ -1447,8 +1564,8 @@
 #if CONFIG_IBC_SR_EXT
     if (ms_params->is_intra_mode &&
         ms_params->cm->features.allow_local_intrabc) {
-      MV sub_mv = { (int16_t)GET_MV_SUBPEL(best_mv.row),
-                    (int16_t)GET_MV_SUBPEL(best_mv.col) };
+      MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv.row),
+                    (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv.col) };
       int flag = av1_is_dv_valid(sub_mv, ms_params->cm, ms_params->xd,
                                  ms_params->mi_row, ms_params->mi_col,
                                  ms_params->bsize, ms_params->mib_size_log2);
@@ -1474,8 +1591,8 @@
 #if CONFIG_IBC_SR_EXT
         if (ms_params->is_intra_mode &&
             ms_params->cm->features.allow_local_intrabc) {
-          MV sub_mv = { (int16_t)GET_MV_SUBPEL(this_mv.row),
-                        (int16_t)GET_MV_SUBPEL(this_mv.col) };
+          MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.row),
+                        (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.col) };
           int flag = av1_is_dv_valid(
               sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
               ms_params->mi_col, ms_params->bsize, ms_params->mib_size_log2);
@@ -1506,8 +1623,8 @@
 #if CONFIG_IBC_SR_EXT
           if (ms_params->is_intra_mode &&
               ms_params->cm->features.allow_local_intrabc) {
-            MV sub_mv = { (int16_t)GET_MV_SUBPEL(this_mv.row),
-                          (int16_t)GET_MV_SUBPEL(this_mv.col) };
+            MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.row),
+                          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.col) };
             int flag = av1_is_dv_valid(
                 sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
                 ms_params->mi_col, ms_params->bsize, ms_params->mib_size_log2);
@@ -1652,7 +1769,10 @@
                           int search_step, const int do_init_search,
                           int *cost_list, FULLPEL_MV *best_mv) {
   static const int search_steps[MAX_MVSEARCH_STEPS] = {
-    10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+#if CONFIG_MV_RANGE_EXTENSION
+    12, 11,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+    10, 9,  8, 7, 6, 5, 4, 3, 2, 1, 0,
   };
   int i, s, t;
 
@@ -1668,6 +1788,11 @@
   int k = -1;
   const MV_COST_PARAMS *mv_cost_params = &ms_params->mv_cost_params;
   search_step = AOMMIN(search_step, MAX_MVSEARCH_STEPS - 1);
+#if CONFIG_MV_RANGE_EXTENSION
+  if (!search_sites->enable_high_motion) {
+    search_step = AOMMAX(search_step, 2);
+  }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   assert(search_step >= 0);
   assert(ms_params->mv_cost_params.pb_mv_precision >= MV_PRECISION_ONE_PEL);
 
@@ -2044,8 +2169,8 @@
 
 #if CONFIG_IBC_SR_EXT
   if (ms_params->is_intra_mode && ms_params->cm->features.allow_local_intrabc) {
-    MV sub_mv = { (int16_t)GET_MV_SUBPEL(start_mv.row),
-                  (int16_t)GET_MV_SUBPEL(start_mv.col) };
+    MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(start_mv.row),
+                  (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(start_mv.col) };
     if (av1_is_dv_valid(sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
                         ms_params->mi_col, ms_params->bsize,
                         ms_params->mib_size_log2)) {
@@ -2090,9 +2215,10 @@
     if (ms_params->is_intra_mode &&
         ms_params->cm->features.allow_local_intrabc) {
       for (j = 0; j < 4; j++) {
-        MV sub_mv = { (int16_t)GET_MV_SUBPEL(best_mv->row + site[1 + j].mv.row),
-                      (int16_t)GET_MV_SUBPEL(best_mv->col +
-                                             site[1 + j].mv.col) };
+        MV sub_mv = {
+          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv->row + site[1 + j].mv.row),
+          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv->col + site[1 + j].mv.col)
+        };
         all_in &= av1_is_dv_valid(sub_mv, ms_params->cm, ms_params->xd,
                                   ms_params->mi_row, ms_params->mi_col,
                                   ms_params->bsize, ms_params->mib_size_log2);
@@ -2112,10 +2238,10 @@
         for (j = 0; j < 4; j++) {
           if (ms_params->is_intra_mode &&
               ms_params->cm->features.allow_local_intrabc) {
-            MV sub_mv = {
-              (int16_t)GET_MV_SUBPEL(best_mv->row + site[idx + j].mv.row),
-              (int16_t)GET_MV_SUBPEL(best_mv->col + site[idx + j].mv.col)
-            };
+            MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(
+                              best_mv->row + site[idx + j].mv.row),
+                          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(
+                              best_mv->col + site[idx + j].mv.col) };
             valid &= av1_is_dv_valid(
                 sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
                 ms_params->mi_col, ms_params->bsize, ms_params->mib_size_log2);
@@ -2159,8 +2285,8 @@
 #if CONFIG_IBC_SR_EXT
           if (ms_params->is_intra_mode &&
               ms_params->cm->features.allow_local_intrabc) {
-            MV sub_mv = { (int16_t)GET_MV_SUBPEL(this_mv.row),
-                          (int16_t)GET_MV_SUBPEL(this_mv.col) };
+            MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.row),
+                          (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(this_mv.col) };
             int valid = av1_is_dv_valid(
                 sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
                 ms_params->mi_col, ms_params->bsize, ms_params->mib_size_log2);
@@ -2294,8 +2420,8 @@
   *best_mv = start_mv;
 #if CONFIG_IBC_SR_EXT
   if (ms_params->is_intra_mode && ms_params->cm->features.allow_local_intrabc) {
-    const MV sub_mv = { (int16_t)GET_MV_SUBPEL(start_mv.row),
-                        (int16_t)GET_MV_SUBPEL(start_mv.col) };
+    const MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(start_mv.row),
+                        (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(start_mv.col) };
     if (av1_is_dv_valid(sub_mv, ms_params->cm, ms_params->xd, ms_params->mi_row,
                         ms_params->mi_col, ms_params->bsize,
                         ms_params->mib_size_log2)) {
@@ -2389,8 +2515,8 @@
         // stores the best valid mv
         if (best_valid_mv.row != best_mv->row ||
             best_valid_mv.col != best_mv->col) {
-          const MV sub_mv = { (int16_t)GET_MV_SUBPEL(best_mv->row),
-                              (int16_t)GET_MV_SUBPEL(best_mv->col) };
+          const MV sub_mv = { (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv->row),
+                              (MV_COMP_DATA_TYPE)GET_MV_SUBPEL(best_mv->col) };
           if (av1_is_dv_valid(sub_mv, ms_params->cm, ms_params->xd,
                               ms_params->mi_row, ms_params->mi_col,
                               ms_params->bsize, ms_params->mib_size_log2)) {
diff --git a/av1/encoder/mcomp.h b/av1/encoder/mcomp.h
index 4d73baa..cdbfb96 100644
--- a/av1/encoder/mcomp.h
+++ b/av1/encoder/mcomp.h
@@ -25,6 +25,17 @@
 
 // The maximum number of steps in a step search given the largest
 // allowed initial step
+#if CONFIG_MV_RANGE_EXTENSION
+#define MAX_MVSEARCH_STEPS 13
+// Enable the use of motion vector in range [-8191, 8191].
+#define MAX_FULL_PEL_VAL ((1 << MV_CLASSES) - 1)
+// Enable the use of motion vector in range [-2047, 2047] for low motion
+#define LOW_MOTION_MAX_FULL_PEL_VAL ((1 << (MV_CLASSES - 2)) - 1)
+// Maximum size of the first step in full pel units
+#define MAX_FIRST_STEP ((1 << MAX_MVSEARCH_STEPS) - 1)
+// Maximum size of the first step in full pel units for low motion
+#define LOW_MOTION_MAX_FIRST_STEP ((1 << (MAX_MVSEARCH_STEPS - 2)) - 1)
+#else
 #define MAX_MVSEARCH_STEPS 11
 // Max full pel mv specified in the unit of full pixel
 #if CONFIG_MV_SEARCH_RANGE
@@ -36,6 +47,7 @@
 #endif  // CONFIG_MV_SEARCH_RANGE
 // Maximum size of the first step in full pel units
 #define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS - 1))
+#endif  // CONFIG_MV_RANGE_EXTENSION
 // Maximum number of neighbors to scan per iteration during
 // WARP_CAUSAL refinement
 // Note: The elements of warp_search_config.neighbor_mask must be at least
@@ -61,6 +73,9 @@
   int searches_per_step[MAX_MVSEARCH_STEPS * 2];
   int radius[MAX_MVSEARCH_STEPS * 2];
   int stride;
+#if CONFIG_MV_RANGE_EXTENSION
+  int enable_high_motion;
+#endif  // CONFIG_MV_RANGE_EXTENSION
 } search_site_config;
 
 typedef struct {
@@ -244,23 +259,46 @@
 #if CONFIG_IBC_BV_IMPROVEMENT
     const int is_ibc_cost,
 #endif
-
     const search_site_config search_sites[NUM_DISTINCT_SEARCH_METHODS],
     int fine_search_interval);
 
 // Sets up configs for fullpixel diamond search method.
-void av1_init_dsmotion_compensation(search_site_config *cfg, int stride);
+void av1_init_dsmotion_compensation(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                    int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                    int stride);
 // Sets up configs for firstpass motion search.
-void av1_init_motion_fpf(search_site_config *cfg, int stride);
+void av1_init_motion_fpf(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                         int stride);
 // Sets up configs for all other types of motion search method.
-void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_nstep(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                        int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                        int stride);
 // Sets up configs for BIGDIA / FAST_DIAMOND / FAST_BIGDIA
 // motion search method.
-void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_bigdia(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                         int stride);
 // Sets up configs for HEX or FAST_HEX motion search method.
-void av1_init_motion_compensation_hex(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_hex(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                      int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                      int stride);
 // Sets up configs for SQUARE motion search method.
-void av1_init_motion_compensation_square(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_square(search_site_config *cfg,
+#if CONFIG_MV_RANGE_EXTENSION
+                                         int enable_high_motion,
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                         int stride);
 
 // Mv beyond the range do not produce new/different prediction block.
 static INLINE void av1_set_mv_search_method(
@@ -355,7 +393,12 @@
 void av1_set_tip_mv_search_range(FullMvLimits *mv_limits);
 #endif  // !CONFIG_TIP_MV_SIMPLIFICATION
 
-int av1_init_search_range(int size);
+int av1_init_search_range(int size
+#if CONFIG_MV_RANGE_EXTENSION
+                          ,
+                          int enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+);
 
 int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params,
                              const FULLPEL_MV start_mv, FULLPEL_MV *best_mv);
diff --git a/av1/encoder/motion_search_facade.c b/av1/encoder/motion_search_facade.c
index 4f13af1..c9b762c 100644
--- a/av1/encoder/motion_search_facade.c
+++ b/av1/encoder/motion_search_facade.c
@@ -101,7 +101,12 @@
     // max mv magnitude and that based on the best ref mvs of the current
     // block for the given reference.
     const int ref_frame_idx = COMPACT_INDEX0_NRS(ref);
-    step_param = (av1_init_search_range(x->max_mv_context[ref_frame_idx]) +
+    step_param = (av1_init_search_range(x->max_mv_context[ref_frame_idx]
+#if CONFIG_MV_RANGE_EXTENSION
+                                        ,
+                                        cpi->oxcf.tool_cfg.enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+                                        ) +
                   mv_search_params->mv_step_param) /
                  2;
   } else {
@@ -1477,10 +1482,17 @@
   struct buf_2d backup_yv12;
   // ref_mv is used to calculate the cost of the motion vector
   const MV ref_mv = kZeroMv;
+#if CONFIG_MV_RANGE_EXTENSION
+  const int max_search_steps = cpi->oxcf.tool_cfg.enable_high_motion
+                                   ? MAX_MVSEARCH_STEPS - 2
+                                   : MAX_MVSEARCH_STEPS - 4;
+#else
+  const int max_search_steps = MAX_MVSEARCH_STEPS - 2;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   const int step_param =
       AOMMIN(cpi->mv_search_params.mv_step_param +
                  cpi->sf.part_sf.simple_motion_search_reduce_search_steps,
-             MAX_MVSEARCH_STEPS - 2);
+             max_search_steps);
   const search_site_config *src_search_sites =
       cpi->mv_search_params.search_site_cfg[SS_CFG_SRC];
   int cost_list[5];
@@ -1638,10 +1650,17 @@
   struct buf_2d backup_yv12;
   // ref_mv is used to calculate the cost of the motion vector
   const MV ref_mv = kZeroMv;
+#if CONFIG_MV_RANGE_EXTENSION
+  const int max_search_steps = cpi->oxcf.tool_cfg.enable_high_motion
+                                   ? MAX_MVSEARCH_STEPS - 2
+                                   : MAX_MVSEARCH_STEPS - 4;
+#else
+  const int max_search_steps = MAX_MVSEARCH_STEPS - 2;
+#endif  // CONFIG_MV_RANGE_EXTENSION
   const int step_param =
       AOMMIN(cpi->mv_search_params.mv_step_param +
                  cpi->sf.part_sf.simple_motion_search_reduce_search_steps,
-             MAX_MVSEARCH_STEPS - 2);
+             max_search_steps);
   const search_site_config *src_search_sites =
       cpi->mv_search_params.search_site_cfg[SS_CFG_SRC];
   int cost_list[5];
diff --git a/av1/encoder/mv_prec.c b/av1/encoder/mv_prec.c
index 982cdc6..5c21368 100644
--- a/av1/encoder/mv_prec.c
+++ b/av1/encoder/mv_prec.c
@@ -458,18 +458,55 @@
                num_mv_class_0);
   } else {
     total_rate += get_symbol_cost(mvctx->joint_shell_set_cdf, 1);
-    total_rate +=
-        get_symbol_cost(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
-                        shell_class - num_mv_class_0);
     update_cdf(mvctx->joint_shell_set_cdf, 1, 2);
-    update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
-               shell_class - num_mv_class_0, num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+      const int map_shell_class = get_map_shell_class(shell_class);
+      total_rate +=
+          get_symbol_cost(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                          map_shell_class - num_mv_class_0);
+      update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                 map_shell_class - num_mv_class_0, num_mv_class_1 - 1);
+      if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+        total_rate += get_symbol_cost(mvctx->joint_shell_last_two_classes_cdf,
+                                      shell_class == MAX_NUM_SHELL_CLASS - 1);
+        update_cdf(mvctx->joint_shell_last_two_classes_cdf,
+                   shell_class == MAX_NUM_SHELL_CLASS - 1, 2);
+      }
+    } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+      total_rate +=
+          get_symbol_cost(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                          shell_class - num_mv_class_0);
+      update_cdf(mvctx->joint_shell_class_cdf_1[pb_mv_precision],
+                 shell_class - num_mv_class_0, num_mv_class_1);
+#if CONFIG_MV_RANGE_EXTENSION
+    }
+#endif  // CONFIG_MV_RANGE_EXTENSION
   }
 #else
-  total_rate += get_symbol_cost(mvctx->joint_shell_class_cdf[pb_mv_precision],
-                                shell_class);
-  update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], shell_class,
-             num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+  if (pb_mv_precision == MV_PRECISION_ONE_EIGHTH_PEL) {
+    const int map_shell_class = get_map_shell_class(shell_class);
+    total_rate += get_symbol_cost(mvctx->joint_shell_class_cdf[pb_mv_precision],
+                                  map_shell_class);
+    update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], map_shell_class,
+               num_mv_class - 1);
+    if (shell_class >= MAX_NUM_SHELL_CLASS - 2) {
+      total_rate += get_symbol_cost(mvctx->joint_shell_last_two_classes_cdf,
+                                    shell_class == MAX_NUM_SHELL_CLASS - 1);
+      update_cdf(mvctx->joint_shell_last_two_classes_cdf,
+                 shell_class == MAX_NUM_SHELL_CLASS - 1, 2);
+    }
+  } else {
+#endif  // CONFIG_MV_RANGE_EXTENSION
+    total_rate += get_symbol_cost(mvctx->joint_shell_class_cdf[pb_mv_precision],
+                                  shell_class);
+    update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], shell_class,
+               num_mv_class);
+#if CONFIG_MV_RANGE_EXTENSION
+  }
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
 
   assert(shell_class >= 0 && shell_class < num_mv_class);
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index b44e2b4..bf476ce 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -235,7 +235,12 @@
   const search_site_config *search_site_cfg =
       cpi->mv_search_params.search_site_cfg[SS_CFG_LOOKAHEAD];
   const int step_param = av1_init_search_range(
-      AOMMAX(frame_to_filter->y_crop_width, frame_to_filter->y_crop_height));
+      AOMMAX(frame_to_filter->y_crop_width, frame_to_filter->y_crop_height)
+#if CONFIG_MV_RANGE_EXTENSION
+          ,
+      cpi->oxcf.tool_cfg.enable_high_motion
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  );
   const SUBPEL_SEARCH_TYPE subpel_search_type = USE_8_TAPS;
   const int force_integer_mv = cpi->common.features.cur_frame_force_integer_mv;
   const MV_COST_TYPE mv_cost_type =
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 24339b4..0a59e13 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -226,7 +226,14 @@
   xd->mi[0]->use_amvd = 0;
 
   step_param = tpl_sf->reduce_first_step_size;
-  step_param = AOMMIN(step_param, MAX_MVSEARCH_STEPS - 2);
+#if CONFIG_MV_RANGE_EXTENSION
+  const int max_search_steps = cpi->oxcf.tool_cfg.enable_high_motion
+                                   ? MAX_MVSEARCH_STEPS - 2
+                                   : MAX_MVSEARCH_STEPS - 4;
+#else
+  const int max_search_steps = MAX_MVSEARCH_STEPS - 2;
+#endif  // CONFIG_MV_RANGE_EXTENSION
+  step_param = AOMMIN(step_param, max_search_steps);
 
   const search_site_config *search_site_cfg =
       cpi->mv_search_params.search_site_cfg[SS_CFG_SRC];
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index ebaacaf..ef9d1af 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -378,6 +378,9 @@
 set_aom_config_var(CONFIG_CTX_MODELS_LINE_BUFFER_REDUCTION 1
                    "Enable to reduce context model line buffer size")
 
+set_aom_config_var(CONFIG_MV_RANGE_EXTENSION 1
+                   "Enable to extend the range of MV")
+
 # This is an encode-only change.
 set_aom_config_var(CONFIG_MV_SEARCH_RANGE 1
                    "Enable a sufficient MV search range.")
diff --git a/common/args.c b/common/args.c
index 62cb59b..7205301 100644
--- a/common/args.c
+++ b/common/args.c
@@ -90,6 +90,12 @@
     GET_PARAMS(enable_extended_sdp);
     GET_PARAMS(enable_mrls);
     GET_PARAMS(enable_tip);
+#if CONFIG_TMVP_SIMPLIFICATIONS_F085
+    GET_PARAMS(enable_mv_traj);
+#endif  // CONFIG_TMVP_SIMPLIFICATIONS_F085
+#if CONFIG_MV_RANGE_EXTENSION
+    GET_PARAMS(enable_high_motion);
+#endif  // CONFIG_MV_RANGE_EXTENSION
     GET_PARAMS(enable_bawp);
     GET_PARAMS(enable_cwp);
 #if CONFIG_D071_IMP_MSK_BLD
diff --git a/tools/aom_entropy_optimizer.c b/tools/aom_entropy_optimizer.c
index 9c0e0c3..a2c0361 100644
--- a/tools/aom_entropy_optimizer.c
+++ b/tools/aom_entropy_optimizer.c
@@ -719,6 +719,15 @@
                        "[NUM_MV_PRECISIONS][CDF_SIZE(SECOND_SHELL_CLASS)]",
                        0, &total_count, 0, mem_wanted, "Inter");
 #else
+#if CONFIG_MV_RANGE_EXTENSION
+    cts_each_dim[0] = ibc == 0 ? NUM_MV_PRECISIONS : 1;
+    cts_each_dim[1] = MAX_NUM_SHELL_CLASS - 1;
+    optimize_cdf_table(&nmvc_cnts->joint_shell_class_cnts[0][0], probsfile, 2,
+                       cts_each_dim,
+                       "static aom_cdf_prob joint_shell_class_cdf_placeholder"
+                       "[NUM_MV_PRECISIONS][CDF_SIZE(MAX_NUM_SHELL_CLASS - 1)]",
+                       0, &total_count, 0, mem_wanted, "Inter");
+#else
     cts_each_dim[0] = ibc == 0 ? NUM_MV_PRECISIONS : 1;
     cts_each_dim[1] = MAX_NUM_SHELL_CLASS;
     optimize_cdf_table(&nmvc_cnts->joint_shell_class_cnts[0][0], probsfile, 2,
@@ -726,8 +735,19 @@
                        "static aom_cdf_prob joint_shell_class_cdf_placeholder"
                        "[NUM_MV_PRECISIONS][CDF_SIZE(MAX_NUM_SHELL_CLASS)]",
                        0, &total_count, 0, mem_wanted, "Inter");
+#endif  // CONFIG_MV_RANGE_EXTENSION
 #endif  // CONFIG_REDUCE_SYMBOL_SIZE
 
+#if CONFIG_MV_RANGE_EXTENSION
+    cts_each_dim[0] = 2;
+    optimize_cdf_table(
+        &nmvc_cnts->joint_shell_last_two_classes_cnts[0], probsfile, 1,
+        cts_each_dim,
+        "static aom_cdf_prob joint_shell_last_two_classes_cdf_placeholder"
+        "[CDF_SIZE(2)]",
+        0, &total_count, 0, mem_wanted, "Inter");
+#endif  // CONFIG_MV_RANGE_EXTENSION
+
     cts_each_dim[0] = 2;
     cts_each_dim[1] = 2;
     optimize_cdf_table(
@@ -758,11 +778,11 @@
 #endif  // !CONFIG_CTX_MV_SHELL_OFFSET_OTHER
     cts_each_dim[0] = NUM_CTX_COL_MV_GTX;
     cts_each_dim[1] = 2;
-    optimize_cdf_table(&nmvc_cnts->col_mv_greter_flags_cnts[0][0], probsfile, 2,
-                       cts_each_dim,
-                       "static aom_cdf_prob col_mv_greter_flags_cdf_placeholder"
-                       "[NUM_CTX_COL_MV_GTX][CDF_SIZE(2)]",
-                       0, &total_count, 0, mem_wanted, "Inter");
+    optimize_cdf_table(
+        &nmvc_cnts->col_mv_greater_flags_cnts[0][0], probsfile, 2, cts_each_dim,
+        "static aom_cdf_prob col_mv_greater_flags_cdf_placeholder"
+        "[NUM_CTX_COL_MV_GTX][CDF_SIZE(2)]",
+        0, &total_count, 0, mem_wanted, "Inter");
 
     cts_each_dim[0] = NUM_CTX_COL_MV_INDEX;
     cts_each_dim[1] = 2;